正则表达式可替换字符串中两个不同词之间的词

时间:2019-02-24 10:54:27

标签: php regex preg-replace

我想使用正则表达式将两个单词ABCMNO之间的一个单词XYZ替换为'',但不替换单词{{1 }}不在ABCMNO之间。

例如,给定以下字符串:

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 ABCMNO之间的三个。

我在PHP的XYZ中尝试了一些正则表达式,但是没有成功。

例如,在此示例中,我不知道如何将preg_replace之外的所有内容都不匹配:

ABC

Here's a test link

在这种情况下,我希望使用正则表达式和/(?<=MNO)(.*)ABC(.*)(?=XYZ)/g

有什么想法吗? 谢谢

2 个答案:

答案 0 :(得分:1)

如果句子中只有MNOXYZ出现一次,这将起作用。

尝试此正则表达式:

ABC(?!.*MNO)(?=.*XYZ)

将每个匹配项替换为空白字符串

Click for Demo

说明:

  • 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,都在MNOXYZ之间  然后将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的字符开头。