有什么区别.*?和.*正则表达式?

Dou*_*oug 126 regex regex-greedy

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

text to extract<number>
Run Code Online (Sandbox Code Playgroud)

我一直在使用(.*?)<,<(.*?)>哪个工作正常,但在阅读了一点regex之后,我才开始想知道为什么我需要?表达式中的.我通过这个网站找到它们之后才这样做,所以我不确定它们之间的区别.

pol*_*nts 162

关于贪婪与非贪婪

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

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

参考


例1:从A到Z.

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

鉴于以下输入:

eeeAiiZuuuuAoooZeeee
Run Code Online (Sandbox Code Playgroud)

模式产生以下匹配:

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

eeeAiiZuuuuAoooZeeee
   \_______________/
    A.* matched, Z can't match
Run Code Online (Sandbox Code Playgroud)

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

eeeAiiZuuuuAoooZeeee
   \______________/
    A.* matched, Z still can't match
Run Code Online (Sandbox Code Playgroud)

这种情况发生了几次,直到最后我们才发现:

eeeAiiZuuuuAoooZeeee
   \__________/
    A.* matched, Z can now match
Run Code Online (Sandbox Code Playgroud)

现在Z可以匹配,所以整体模式匹配:

eeeAiiZuuuuAoooZeeee
   \___________/
    A.*Z matched
Run Code Online (Sandbox Code Playgroud)

相比之下,A.*?Z第一次匹配的不情愿重复尽可能少.,然后.根据需要采取更多.这解释了为什么它在输入中找到两个匹配项.

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

eeeAiiZuuuuAoooZeeee
   \__/r   \___/r      r = reluctant
    \____g____/        g = greedy
Run Code Online (Sandbox Code Playgroud)

示例:替代方案

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

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

两种模式之间的主要区别在于性能:更严格,否定的字符类只能匹配给定输入的一种方式.如果你对这个模式使用贪婪或不情愿的修饰符并不重要.事实上,在某些风格中,你可以做得更好,并使用所谓的占有量词,它根本不会回溯.

参考


例2:从A到ZZ

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

eeAiiZooAuuZZeeeZZfff
Run Code Online (Sandbox Code Playgroud)

这些是上述输入的匹配:

以下是它们匹配的直观表示:

         ___n
        /   \              n = negated character class
eeAiiZooAuuZZeeeZZfff      r = reluctant
  \_________/r   /         g = greedy
   \____________/g
Run Code Online (Sandbox Code Playgroud)

相关话题

这些是stackoverflow上的问题和答案的链接,涵盖了一些可能感兴趣的主题.

一个贪婪的重复可以超越另一个

  • 我的意思是 rubular.com,而不是 ideone.com。对于其他人:不要为我修改这篇文章,我会在下次修改时自己修改这篇文章以及其他示例。请随意在评论中提供反馈、建议等,以便我也可以将它们纳入其中。 (3认同)
  • 这个答案已被添加到[Stack Overflow Regular Expression FAQ](http://stackoverflow.com/a/22944075/2736496),在"Quantifiers>更多差异......"下. (3认同)
  • 这个答案确实值得被选择的答案!非常感谢您的详细解释。 (3认同)
  • 另见:http://stackoverflow.com/questions/3145023/performance-and-practice-of-lazy-regex (2认同)

Kob*_*obi 149

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

考虑输入101000000000100.

使用1.*1,*贪婪 - 它将一直匹配到最后,然后回溯直到它可以匹配1,留下你1010000000001.
.*?不贪心.*什么都不匹配,但之后会尝试匹配额外的字符,直到它匹配1,最终匹配101.

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

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

参见Quantifier Cheat Sheet.

  • 当然.对于字符串`"abc"`,正则表达式`/\w\w?\ w /`将匹配完整的字符串``"abc"`` - 因为`?`是贪婪的.`/\w\w ??\w /`是懒惰的 - 它只会匹配`"ab"`.如果以后失败,它只会回溯并匹配"abc". (4认同)

Sim*_*mon 16

假设你有:

<a></a>
Run Code Online (Sandbox Code Playgroud)

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

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

  • 这比上面的解释更容易理解。 (2认同)
  • 解释应该是这样的。 (2认同)