非贪婪通配符 "ignored"

Non-greedy wildcard "ignored"

我遇到了以下情况:

...    
preg_match('/#(.+?):(.+?)#/im','partA#partB#partC:partD#partE#partF',$matches);
...

执行后 $matches 变为

 Array
    (
        [0] => #partB#partC:partD#
        [1] => partB#partC
        [2] => partD
     )

如果我使用非贪婪通配符?$matches[1]变成partC不是很正常吗?我错过了什么吗?

我设法通过使用'/#([^#]+?):([^#]+?)#/im'作为模式来解决它,但是中肯的解释将是清除云层的好方法。

谢谢。

捕获组 1 正在寻找 #,然后是任何内容(不包括新行),直到第一个 :。所以 partB#partC 是有道理的。

你的修改器也没有做任何事情。您没有区分大小写的字母,也没有使用锚点。

您可以在此处查看正则表达式的处理方式,https://regex101.com/r/iS0lW9/1

当你思考正则表达式背后的基础理论时,它就有意义了。

正则表达式就是所谓的 finite state automaton (FSA)。这意味着它本质上会从左到右一次处理一个字符,偶尔会向后 "giving up" 个字符。在你的例子中,正则表达式看到第一个 # 并且注意到 # 没有参与模式的任何其他部分,开始匹配下一个标记(.+?,在你的案件)。它会一直这样做,直到遇到冒号,然后匹配下一个标记(同样是 .+?)。因为它是从左到右,它会匹配到第一个散列,然后停止,因为它是懒惰的。

这实际上是一个常见的误解 - 量词的 ? 修饰符不是 非贪婪的 ,它是 惰性的 .它将匹配最小可能的字符串,从左到右

要修复您原来的正则表达式,您可以这样修改它:

/.+#(.+?):(.+?)#/im

这样做是在冒号之前的最后一个散列之前使用贪婪匹配,强制第一个捕获组只使用该散列和冒号之间的内容。同样,该组也不需要 lazy 修饰符,从而产生最终的正则表达式:

/.+#(.+):(.+?)#/im