我想使用正则表达式将两个单词ABC
和MNO
之间的一个单词XYZ
替换为''
,但不替换单词{{1 }}不在ABC
和MNO
之间。
例如,给定以下字符串:
XYZ
预期结果将是:
Lorem ABC ipsum ABC bla MNO bla ipsum ABC asfg 123 hello ABC dd ABC XYZ hello ABC
因此,唯一被替换的Lorem ABC ipsum ABC bla MNO bla ipsum asfg 123 hello dd XYZ hello ABC
是ABC
和MNO
之间的三个。
我在PHP的XYZ
中尝试了一些正则表达式,但是没有成功。
例如,在此示例中,我不知道如何将preg_replace
之外的所有内容都不匹配:
ABC
在这种情况下,我希望使用正则表达式和/(?<=MNO)(.*)ABC(.*)(?=XYZ)/g
。
有什么想法吗? 谢谢
答案 0 :(得分:1)
如果句子中只有MNO
和XYZ
出现一次,这将起作用。
尝试此正则表达式:
ABC(?!.*MNO)(?=.*XYZ)
将每个匹配项替换为空白字符串
说明:
ABC
-匹配ABC
(?!.*MNO)
-否定超前查询,以确保当前匹配项后面的字符串中的某个地方MNO
之后没有出现(?=.*XYZ)
-正向查找,以确保在当前匹配项之后的字符串后面的某个地方XYZ
代码(RESULT)
$re = '/ABC(?!.*MNO)(?=.*XYZ)/m';
$str = 'Lorem `ABC` ipsum ABC bla MNO bla ipsum ABC asfg 123 hello ABC dd ABC XYZ hello ABC
';
$subst = '';
$result = preg_replace($re, $subst, $str);
echo "The result of the substitution is ".$result;
答案 1 :(得分:1)
您可以使用preg_replace_callback
:
$s = preg_replace_callback('~(MNO)(.*?)(XYZ)~s', function($m) {
return $m[1] . str_replace('ABC', 'XXX', $m[2]) . $m[3];
}, $s);
或者通过环顾四周,使匿名函数中的代码更加精简:
$s = preg_replace_callback('~(?<=MNO).*?(?=XYZ)~s', function($m) {
return str_replace('ABC', 'XXX', $m[0]);
}, $s);
请参见PHP demo
这里,(MNO)(.*?)(XYZ)
匹配并捕获MNO
,都在MNO
和XYZ
之间
然后将XYZ
分为三组,并在匿名函数内部,所有ABC
仅在第二组中被替换。请注意,正则表达式末尾的s
标志也必须使.
匹配换行符。
在第二个示例中,(?<=MNO)
是正向后方,不消耗文本,并且要求MNO
立即出现在当前位置的左侧,而(?=XYZ)
是正向前瞻性要求XYZ
立即出现在当前位置的右侧,并且也不占用文本,因此,这里不需要分组。
使用preg_replace
更加困难:
preg_replace('~(?:\G(?!\A)|MNO)(?:(?!MNO).)*?\KABC(?=(?:(?!MNO).)*?XYZ)~s', 'XXX', $s)
请参见regex demo。
详细信息
(?:\G(?!\A)|MNO)
-上一场比赛结束或MNO
(?:(?!MNO).)*?
-不会开始MNO
字符序列的任何1个字符,0个或更多出现(少至可能),\K
-匹配重置运算符,它丢弃匹配缓冲区中的文本ABC
-一个ABC
(?=(?:(?!MNO).)*?XYZ)
-在右边,必须有0个以上的字符(尽可能少),这些字符不能以MNO
后跟XYZ
的字符开头。