非贪婪的通配符"忽略"

时间:2016-08-30 19:28:42

标签: php regex preg-match regex-greedy

我遇到以下情况:

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

执行后$ match变为

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

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

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

感谢。

2 个答案:

答案 0 :(得分:1)

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

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

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

答案 1 :(得分:1)

当你考虑正则表达式背后的基础理论时,这是有道理的。

正则表达式是所谓的finite state automaton (FSA)。这意味着它本质上会从左到右一次处理你的字符串一个字符,偶尔会倒退#34;放弃"字符。在您的示例中,正则表达式会看到第一个#,并注意到#没有参与模式的任何其他部分,开始匹配下一个标记(.+?,在你的情况下)。它会一直到结肠,然后匹配下一个标记(再次,.+?)。由于它是从左到右,它会匹配第一个哈希,然后停止,因为它是懒惰的。

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

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

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

这样做会在冒号前的最后一个哈希值之前使用贪婪匹配,强制第一个捕获组仅使用该哈希值和冒号之间的内容。同样,该组也不需要延迟修饰符,产生最终的正则表达式:

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