PHP正则表达式中的反向引用条件是如何工作的?

PHP正则表达式中的反向引用条件是如何工作的?,php,regex,Php,Regex,我的要求如下: 如果字符串包含单词cat,则必须匹配cat。 但是,如果单词cat前面有单词dog,那么cat后面还必须有dog,并且所有3个单词都必须匹配。 这意味着不能匹配字符串dog cat,因为第二个dog不存在。 因此,我用PHP编写了以下正则表达式。它包含一个反向参考条件: $ptn = '@' . // PHP delimiter '(dog\s*)?' . // dog

我的要求如下:

如果字符串包含单词cat,则必须匹配cat。 但是,如果单词cat前面有单词dog,那么cat后面还必须有dog,并且所有3个单词都必须匹配。 这意味着不能匹配字符串dog cat,因为第二个dog不存在。 因此,我用PHP编写了以下正则表达式。它包含一个反向参考条件:

      $ptn = '@' .                    // PHP delimiter
             '(dog\s*)?' .            // dog
             'cat\s*' .               // cat
             '(?(1)dog)' .            // backreference cond
             '@';                     // PHP delimiter
正则表达式满足第1条要求:

     $str1b = 'cat';
     preg_match($ptn, $str1b, $matches);
     print_r($matches);
O/p为:

数组[0]=>cat

正则表达式还满足第2条要求:

     $str1a = 'dog cat dog';
     preg_match($ptn, $str1a, $matches);
     print_r($matches);
O/p为:

数组[0]=>狗猫狗[1]=>狗

但是,我想问为什么数组包含2个元素?是因为正则表达式有2个子表达式吗

现在谈谈要求3。以下数据对其进行了测试:

      $str1c = 'dog cat';
      preg_match($ptn, $str1c, $matches);
      print_r($matches);
此处的O/p为:

数组[0]=>cat

在这里,我想问:

为什么猫是配对的?因为前面有狗,所以后面也应该有狗,这会导致一场比赛;否则就不应该发生匹配

这就是正则表达式的工作原理吗

我如何达到我的3个要求

这是我的建议


我正在考虑只使用PHP的解决方案。

在使用捕获组时,您将获得2个匹配项

使用您尝试的模式dog\s*?cat\s*?1dog,您可以得到一个猫对狗猫的匹配

这是因为模式可以选择性地匹配狗。若有狗,它会被抓获,然后尝试匹配猫

然后在if子句中声明:如果我们有第1组,则匹配狗。发生的情况是,如果组1中没有匹配项,它仍然可以匹配cat,因为捕获组1是可选的

因此,在“狗-猫”中,它最终无法与“狗”匹配,但当尝试从“猫”开始时,它可以与后面的“猫”匹配

如果你想匹配所有3个单词“狗-猫-狗”或只匹配一只猫,而你不想匹配“狗-猫”,你可以使用

\b(?:dog cat dog|dog cat\b(*SKIP)(*F)|cat)\b
\b防止部分匹配的单词边界 ?:非捕获组 狗猫狗狗比赛 |或 狗猫\b*跳过*F如果狗猫跳过比赛 |或 猫只会数学 关闭非捕获组 \b单词边界 |

比如说

$strings = [
    "cat",
    "dog cat dog",
    "dog cat",
    "cat dog",
    "this cat cat is a test dog cat dog cat"
];
$pattern = "/\b(?:dog cat dog|dog cat\b(*SKIP)(*F)|cat)\b/";
foreach ($strings as $str) {
    preg_match_all($pattern, $str, $matches);
    print_r($matches[0]);
}
输出

Array
(
    [0] => cat
)
Array
(
    [0] => dog cat dog
)
Array
(
)
Array
(
    [0] => cat
)
Array
(
    [0] => cat
    [1] => cat
    [2] => dog cat dog
    [3] => cat
)
另一种使用捕获组的方法是匹配您想要避免的内容,并捕获您想要保留的内容。对于匹配的空格,可以使用\s,但请注意,它也可以匹配换行符

\bdog cat\b(?! dog\b)|\b(dog cat dog|cat)\b
如果一个量词在lookback断言中可用,您也可以使用

\bdog cat dog\b|(?<!dog *)\bcat\b|cat(?= *dog\b)

在使用捕获组时,您将获得2个匹配项

使用您尝试的模式dog\s*?cat\s*?1dog,您可以得到一个猫对狗猫的匹配

这是因为模式可以选择性地匹配狗。若有狗,它会被抓获,然后尝试匹配猫

然后在if子句中声明:如果我们有第1组,则匹配狗。发生的情况是,如果组1中没有匹配项,它仍然可以匹配cat,因为捕获组1是可选的

因此,在“狗-猫”中,它最终无法与“狗”匹配,但当尝试从“猫”开始时,它可以与后面的“猫”匹配

如果你想匹配所有3个单词“狗-猫-狗”或只匹配一只猫,而你不想匹配“狗-猫”,你可以使用

\b(?:dog cat dog|dog cat\b(*SKIP)(*F)|cat)\b
\b防止部分匹配的单词边界 ?:非捕获组 狗猫狗狗比赛 |或 狗猫\b*跳过*F如果狗猫跳过比赛 |或 猫只会数学 关闭非捕获组 \b单词边界 |

比如说

$strings = [
    "cat",
    "dog cat dog",
    "dog cat",
    "cat dog",
    "this cat cat is a test dog cat dog cat"
];
$pattern = "/\b(?:dog cat dog|dog cat\b(*SKIP)(*F)|cat)\b/";
foreach ($strings as $str) {
    preg_match_all($pattern, $str, $matches);
    print_r($matches[0]);
}
输出

Array
(
    [0] => cat
)
Array
(
    [0] => dog cat dog
)
Array
(
)
Array
(
    [0] => cat
)
Array
(
    [0] => cat
    [1] => cat
    [2] => dog cat dog
    [3] => cat
)
另一种使用捕获组的方法是匹配您想要避免的内容,并捕获您想要保留的内容。对于匹配的空格,可以使用\s,但请注意,它也可以匹配换行符

\bdog cat\b(?! dog\b)|\b(dog cat dog|cat)\b
如果一个量词在lookback断言中可用,您也可以使用

\bdog cat dog\b|(?<!dog *)\bcat\b|cat(?= *dog\b)
但是,如果单词cat前面有单词dog,那么cat后面还必须有dog,并且所有3个单词都必须匹配

根据我的解释,此正则表达式可能也适用于您:

\b:狗猫狗? 正则表达式详细信息:

\b:词界 ?::启动非捕获组 狗猫狗:匹配狗猫狗 |: ?:如果前面没有单词dog和空格,则匹配cat :结束非捕获组 \b:词界 但是,如果单词cat前面有单词dog,那么cat后面还必须有dog,并且所有3个单词都必须匹配

根据我的解释,此正则表达式可能也适用于您:

\b:狗猫狗? 正则表达式详细信息:

\b:词界 ?::启动非捕获组 狗猫狗:匹配狗猫狗 |: ?:如果前面没有单词dog和空格,则匹配cat :结束非捕获组 \b:词界 这是一个例子

它匹配狗和猫,但不匹配狗和猫

我无法在这里发布正则表达式,因为SO声称它没有正确缩进,尽管它是。请检查正则表达式的链接。

这里有一个

它匹配狗和猫,但不匹配狗和猫

我无法在这里发布正则表达式,因为SO声称它没有正确缩进

是的。请检查正则表达式的链接。

你是说像这样吗\你是说像这样吗\是的,你的正则表达式是有效的。我只是想知道为什么我用的正则表达式没有。当反向参考条件声明它不应该匹配时,它匹配了dog-cat。@ssten即使使用您尝试的模式dDog\s*?cat\s*?1dog,您也会得到一个猫中猫的匹配,这是因为如果有狗它尝试匹配cat,则该模式会选择性地匹配狗。然后在if子句中声明:如果我们有第1组,则匹配狗。发生的情况是,如果组1中没有狗,它仍然可以匹配猫,因为捕获组1是可选的。因此,在《狗猫》中,它最终无法与《狗》相匹敌,但下一只猫在尝试以《猫》开始时,它可以与之匹敌。@anubhava我认为是这样,我还在regex演示中添加了一个这样的示例,以匹配猫狗猫狗中的最后一只猫,这样猫狗猫具有优先权。@anubhava我认为它将匹配该猫,就像第一个要求一样,如果字符串包含单词cat,cat必须匹配。你可以随时发布答案,我是你出色解决方案的粉丝:-@Thefourthbird,是的,我看到了。你说得对。是的,你的正则表达式有效。我只是想知道为什么我用的正则表达式没有。当反向参考条件声明它不应该匹配时,它匹配了dog-cat。@ssten即使使用您尝试的模式dDog\s*?cat\s*?1dog,您也会得到一个猫中猫的匹配,这是因为如果有狗它尝试匹配cat,则该模式会选择性地匹配狗。然后在if子句中声明:如果我们有第1组,则匹配狗。发生的情况是,如果组1中没有狗,它仍然可以匹配猫,因为捕获组1是可选的。因此,在《狗猫》中,它最终无法与《狗》相匹敌,但下一只猫在尝试以《猫》开始时,它可以与之匹敌。@anubhava我认为是这样,我还在regex演示中添加了一个这样的示例,以匹配猫狗猫狗中的最后一只猫,这样猫狗猫具有优先权。@anubhava我认为它将匹配该猫,就像第一个要求一样,如果字符串包含单词cat,cat必须匹配。你可以随时发布答案,我是你出色解决方案的粉丝:-@Thefourthbird,是的,我看到了。你是对的。永远是一件愉快的事+++@anubhava,你为dog-cat-dog@anubhava提供的解决方案,请尝试我已经在我的评论中发布的repl链接。你正在使用\b?=dog-cat-dog |?在你的演示中,这和我的回答不一样。@anubhava,我已经用你的回答试过了。它工作正常。始终是一个愉快的+++@anubhava,您的狗猫狗@anubhava解决方案,请尝试我在评论中已经发布的repl链接。您使用的是\b?=狗猫狗|?在你的演示中,这和我的回答不一样。@anubhava,我已经用你的回答试过了。它工作正常。