PHP理解贪婪匹配和非贪婪匹配

7

This:

preg_match('~foo(.*?)(bar)?~','foo bar',$m);

给我这个:

Array
(
    [0] => foo
    [1] => 
)

我对此有些困惑。我知道第一组给了我一个空字符串,因为它是一个懒惰匹配。但是(bar)?不应该是贪婪的吗?这样岂不是应该给我捕获组2?

在我看来,我应该得到的是:

Array
(
    [0] => foo
    [1] => 
    [2] => bar
)

其中 [1] 表示一个空格。然而,这并没有发生。为什么?


6
不相关话题:请将您的名称更改为“mysqli_noobie...”。了解有关prepared statements的知识,并使用PDOMySQLi——本文将帮助您决定该选择哪个。如果您选择PDO,这里有一个很好的教程 - HamZa
1
@HamZa 这让我笑了! - IMSoP
1
如果它按照你的期望工作,[0] 实际上应该是 "foo bar"。[0] 是完整的匹配。 - Johannes H.
请查看我编辑的答案,它可以解决你的困惑。 :) - Johannes H.
@JohannesH。yar,我忘记了我在玩它时已经包装了“foo”,所以我很困惑。谢谢! - slinkhi
@mysql_noobie_xxxx,你可以在regex101.com上玩一下,它很时尚且速度很快 :) - HamZa
3个回答

5
这里的答案出人意料地简单。第一组最初没有匹配到任何内容,甚至不包括空格。第二组试图用 "bar" 匹配空格,当然失败了。如果后面有必须匹配的内容,引擎将回溯并扩展第一个捕获组以匹配空格。但现在它的状态非常好(第二组实际上可以为空),所以保持不变即可。
要得到您所期望的结果,请尝试这样做:
preg_replace('~foo(.*?)(bar)?_~', 'foo bar_', $m);

在您进行编辑时,您添加了另一个捕获组。(.*)现在是2。它匹配到字符串的结尾,正如您所想的那样。所以您在这一点上是正确的,只是您改变了示例^^

1
是的,我发帖后就意识到了这一点,然后明白它不是最后一个弹出的“bar”,而是(.*),谢谢! - slinkhi

3
不,这种行为是正确的。根据懒惰匹配的文档
如果量词后跟着一个问号,则它变成了懒惰模式,并且只匹配可能的最小次数 由于(bar)?是可选的,(.*?)不需要匹配任何内容就可以使正则表达式成功。由于“foo”和“bar”之间的空格没有被捕获,所以表达式无法继续匹配“bar”。

2

条目“0”始终匹配完整模式,本例中为foo。 然而,第一个匹配组因使用了*而没有匹配任何内容。第二个组是可选的。


那并没有真正回答问题。实际上,如果第一组不懒惰的话,第二组就会占据这个位置,即使它仍然是可选的。 - Johannes H.
@JohannesH. 呃.. (foo)(.*)(bar)? 确实在 [2] 中给了我 "bar".. 为什么呢? - slinkhi
1
这是因为所有的捕获组都是贪婪的。这意味着它们会尽可能匹配更多内容。当然,(foo)会匹配foo(在[1]中)。(.*)匹配空格 - 和(bar)(在[2]中)。(bar)?不匹配任何内容(所以没有[3])。 - Johannes H.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接