使一个或零正则表达式运算符贪婪

时间:2013-09-18 07:16:57

标签: php regex greedy regex-greedy non-greedy

我有两个句子作为输入。比方说吧:

<span>I love my red car.</span>
<span>I love my car.</span>

现在我想匹配span-tags内的每个textpart(如果可用的颜色)。

如果我使用以下正则表达式:

/<span>(.*?)(?P<color>red)(.*?)<\/span>/ms

仅匹配具有颜色的线条。所以我认为让我们使用?-operator(一个或零)。

/<span>(.*?)(?P<color>red)?(.*?)<\/span>/ms

现在两行/句子都会匹配。可悲的是,颜色不再匹配了。

问题是为什么?通过使用 ”。*?”在颜色部分之前,我以为我已经使正则表达式非贪婪,所以颜色部分会匹配,如果它存在的话。但正如所说,它没有......

2 个答案:

答案 0 :(得分:5)

第一个(.*?)将在>I之间匹配,因为它是懒惰的,它会立即测试正则表达式的下一部分:(?P<color>red)?但是没有{ {1}}此时,red'的0选项激活',正则表达式继续到下一部分?。它会再次匹配(.*?)>之间的部分,因为它是懒惰的,它会检查正则表达式的下一部分:I(我将它作为一个整体)

所以第二个<\/span>将一直匹配。

的确,您的(.*?)将为空results[1](我不记得您是否必须引用results[color]color将包含results[3] I love my red car.

嗯,一个解决方法就是在他的回答中使用像NickC那样的OR。您可能使用的另一种方法是使用否定前瞻来检查每个字符:

<span>((?:(?!\bred\b).)*(?<colour>\bred\b)?.*)<\/span>

regex101 demo

作为旁注,我建议您使用边界一词,以免与reducejarred等内容相匹配。

答案 1 :(得分:2)

这应该有效:

/<span>(.*?(?P<color>red).*?|.*?)<\/span>/ms

你的原始表达非常好。我稍微修改它以使新的外部组匹配整个句子。我使用那个新的外部组来创建一个“或”条件来匹配“任何东西”,以防颜色不存在。

缩写输出:

Array
    [0] => Array
            [0] => <span>I love my red car.</span>
            [1] => <span>I love my car.</span>

    [1] => Array
            [0] => I love my red car.
            [1] => I love my car.

    [color] => Array
            [0] => red
            [1] =>