。*和有什么不一样?和。*正则表达式?


142

我正在尝试使用正则表达式将字符串分成两部分。字符串的格式如下:

text to extract<number>

我一直在使用(.*?)<<(.*?)>并且工作正常,但是在阅读了正则表达式后,我才开始怀疑为什么?在表达式中需要使用。在通过本网站找到他们之后,我才这样做,所以我不确定是否有什么区别。


Answers:


172

这是贪婪和非贪婪量词之间的区别。

考虑输入101000000000100

使用1.*1*是贪婪的-它会一直匹配到最后,然后回溯直到可以匹配为止1,剩下的就是您1010000000001
.*?是非贪婪的。*将不匹配任何内容,但随后将尝试匹配多余的字符,直到匹配为止1,最终匹配101

所有的量词有一个非贪婪模式:.*?.+?.{2,6}?,甚至.??

在你的情况下,类似的模式可能是<([^>]*)>-匹配任何东西,但一个大于号(严格来说,它的其他零个或多个字符匹配比>在中间<>)。

请参阅量化器备忘单


太好了,我喜欢最后一个,除了>号!
道格2010年

1
您能否解释或显示贪婪?与非贪婪??有何不同的示例?
AdrianHHH 2015年

4
当然。对于字符串"abc",正则表达式/\w\w?\w/将匹配完整的字符串"abc"-因为它?很贪心。/\w\w??\w/很懒-它只会匹配"ab""abc"如果稍后失败,它将仅回溯并匹配。
科比2015年

184

贪婪与非贪婪

默认情况下,正则表达式中的重复是贪婪的:他们尝试匹配尽可能多的代表,而当这不起作用并且必须回溯时,他们尝试一次匹配更少的代表,直到匹配整个模式为止找到了。结果,当匹配最终发生时,贪婪的重复将匹配尽可能多的重复。

?作为的重复数量更改此行为成为非贪婪,也被称为不愿在例如,Java)(有时候“懒”)。相比之下,此重复将首先尝试匹配尽可能少的代表,并且当此重复不起作用并且必须回溯时,他们将开始每次匹配一个代表。结果,当比赛最终发生时,勉强的重复将匹配尽可能少的次数。

参考资料


示例1:从A到Z

让我们比较一下这两种模式:A.*ZA.*?Z

给出以下输入:

eeeAiiZuuuuAoooZeeee

模式产生以下匹配:

让我们首先关注什么A.*Z。当它匹配的第一个A,在.*,贪婪,首先尝试匹配尽可能多.地。

eeeAiiZuuuuAoooZeeee
   \_______________/
    A.* matched, Z can't match

由于Z不匹配,因此引擎会回溯,然后.*必须少匹配一个.

eeeAiiZuuuuAoooZeeee
   \______________/
    A.* matched, Z still can't match

这又发生了几次,直到最后我们来到这里:

eeeAiiZuuuuAoooZeeee
   \__________/
    A.* matched, Z can now match

现在Z可以匹配,因此总体模式匹配:

eeeAiiZuuuuAoooZeeee
   \___________/
    A.*Z matched

相比之下,在A.*?Z最初的匹配中,勉强重复的次数.越少越好,然后.根据需要进行更多的重复。这解释了为什么它在输入中找到两个匹配项。

这是两种模式匹配的直观表示:

eeeAiiZuuuuAoooZeeee
   \__/r   \___/r      r = reluctant
    \____g____/        g = greedy

示例:替代

在许多应用中,上面的输入中的两个匹配是所希望的,因此使用了一个不情愿.*?而不是贪婪的方法.*来防止过度匹配。但是,对于这种特定模式,使用否定字符类是更好的选择。

该模式A[^Z]*Z还找到与A.*?Z上述输入的模式相同的两个匹配项(如ideone.com所示)。[^Z]是所谓的否定字符类:它除了匹配任何东西Z

两种模式之间的主要区别在于性能:更严格地说,否定的字符类只能为给定输入匹配一种方式。对这个模式使用贪婪或勉强的修饰符都没关系。实际上,在某些情况下,您甚至可以做得更好,并使用所谓的所有格量词,它根本不会回溯。

参考资料


示例2:从A到ZZ

这个例子应该是说明性的:它显示了在相同的输入下,贪婪的,不情愿的和否定的字符类模式如何不同地匹配。

eeAiiZooAuuZZeeeZZfff

这些是上述输入的匹配项:

这是它们匹配内容的直观表示:

         ___n
        /   \              n = negated character class
eeAiiZooAuuZZeeeZZfff      r = reluctant
  \_________/r   /         g = greedy
   \____________/g

相关话题

这些是指向stackoverflow的问题和解答的链接,这些问题和解答涵盖了可能感兴趣的一些主题。

一个贪婪的重复可能会超过另一个


1
我的意思是说rubular.com,而不是ideone.com。对其他人:不要为我修改此帖子,我会在下一个修订版本中与其他示例一起自己做。随时在评论中提供反馈,建议等,这样我也可以将其合并。
polygenelubricants 2010年


4
此答案已添加到堆栈溢出正则表达式常见问题解答中的 “量词>关于差异的更多信息...”下
aliteralmind 2014年

这个答案确实值得被选择!非常感谢您的详细说明。
masky007

我添加了标签non-greedy。为什么,因为这个问题需要它,还因为它会将更多的用户吸引到这个很好的答案中。换句话说,如果您给出了一个很好的答案,而答案使用的不是问题中的标签,则添加标签,因为OP不知道该标签是真实的。
Guy Coder

20

假设您有:

<a></a>

<(.*)>将匹配a></a在那里为<(.*?)>将匹配a。后者在的第一场比赛后停止>。它检查一个或0个匹配项,.*后跟下一个表达式。

<(.*)>匹配第一个表达式时,第一个表达式不会停止>。它将持续到的最后一场比赛>


比上面的解释更容易理解。
普罗米修斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.