2016-08-30 71 views
1

我得到了以下情况:非贪婪通配符“忽略”

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

执行$比赛后成为

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

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

我设法通过使用'/#([^#]+?):([^#]+?)#/im'作为模式来解决这个问题,但一个相关的解释对于清除云是很好的。

感谢。

+1

实际上,你可以使用''/#([^#:] +)([^#] +)#/“'。重点是* lazy *量词不保证最短匹配,并且正则表达式引擎(默认)从左到右处理字符串。一旦找到有效的符号,就会从最左边的位置到右边尝试其余的模式。所以,'partB#partC'对'。+?'可以。 –

+1

要理解,正则表达式引擎从左到右搜索字符串,并尝试在字符串中的每个位置成功。 –

+1

我在你的正则表达式'#'中看到':'到'#'。与'abc'匹配############################################# ################################:#'def'。你看到的是'#:#'。原因在于你想看到的是人性。 – sln

回答

1

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

正则表达式就是所谓的finite state automaton (FSA)。这意味着它本质上会一次处理一个字符,从左到右,偶尔会通过“放弃”字符倒退。在你的例子中,正则表达式看到第一个#,并注意到#没有参与模式的任何其他部分,开始匹配下一个标记(在你的情况下为.+?)。它会这样做,直到它遇到冒号,然后匹配下一个令牌(再次,.+?)。由于它是从左到右,它会匹配到第一个散列,然后停止,因为它是懒惰的。

这其实是一个普遍的误解 - 对?修改的量词是不是非贪婪,这是。它将匹配最小可能的字符串,从左到右

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

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

这是什么会做的是冒号前的最后一个散列之前使用一个贪婪的比赛,迫使第一捕获组到仅使用散列和冒号之间的东西。本着同样的精神,这个小组将不需要懒惰修改或者,产生最终的正则表达式:

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

感谢您发现非贪婪/懒惰的差异。放这样的话真的很有意义。 – Radacina

+1

@Radacina:如果答案是有用的,通常在SO上,使用投票箭头旁边的复选标记按钮将其标记为您的问题的答案。这有助于其他人找到他们问题的答案,因为那样他们就不必在问题的整个答案部分寻找答案。 –

1

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

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

你可以看到你的正则表达式在这里如何处理https://regex101.com/r/iS0lW9/1

+0

是的,我现在明白为什么它像这样对待它,它是有道理的。感谢修改器的注释。 – Radacina