正则表达式占有量对抗懒惰或贪婪

时间:2010-07-15 06:54:22

标签: java regex

任何人都可以一步一步解释我为什么正则表达式失败了:

<.++>

使用此字符串进行比较:<em>

在懒惰或贪婪量词中找到相同的字符串,但在这种情况下 涉及哪些步骤?

我使用Java正则表达式。

3 个答案:

答案 0 :(得分:12)

来自Java Pattern documentation

  

占有量词,尽可能地贪婪地匹配并且不会退缩,即使这样做也会使整体比赛成功。

在您的示例中,正则表达式中的<与字符串中的<匹配,然后.++匹配字符串的其余部分em>。您的正则表达式中仍然有>,但字符串中没有字符可供匹配(因为.++全部消耗了它们)。所以比赛失败了。

如果量词是贪婪的,即如果它是.+而不是.++,那么正则表达式引擎会尝试将.+匹配的部分减少一个字符,只需em,然后重试。这次匹配会成功,因为字符串中会留下>,以便匹配正则表达式中的>

编辑:懒惰的量词会像贪婪的量词一样反过来。懒惰量词将首先尝试匹配单个字符,在这种情况下只是e,而不是尝试匹配字符串的其余部分并逐个字符地退出。如果这不允许完整正则表达式匹配(这不会在这里,因为你在正则表达式中>试图匹配字符串中的m),懒惰的量词会移动最多匹配两个字符em。然后正则表达式中的>将与字符串中的>对齐,匹配将成功。但是,如果它没有成功,那么延迟量词将最多移动三个字符,依此类推。

答案 1 :(得分:4)

Possessive quantifier会阻止回溯 - 因此.++部分会与剩余的字符串em>匹配,同时也会占用最后一个>

因此正则表达式的最后>没有匹配且正则表达式失败。

  

就像贪婪的量词一样,占有量词会尽可能多地重复令牌。与贪婪的量词不同,它不会因为引擎回溯而放弃匹配。通过占有量词,交易全部或全无。您可以通过在其后面添加额外的+来使量词占有。

答案 2 :(得分:3)

关于贪婪的变种

首先让我们考虑像<.+>这样的模式如何与<em>匹配:

  • 模式中的<与输入中的<匹配。
  • 然后.+匹配输入中的em>(因为它贪婪,它首先匹配尽可能多的.
    • 然后>不匹配,因为输入中没有其他字符
  • 此时.+回溯并且必须少一个.;所以.+现在匹配em
  • 模式中的>现在与输入中的>匹配。

关于不情愿的变种

相比之下,这是<.+?><em>匹配的方式:

  • 模式中的<与输入中的<匹配。
  • 然后.+?匹配输入中的e(因为它不情愿,但必须至少有一个.
    • 然后>不匹配,因为输入的其余部分为m>
  • 此时.+回溯并且必须再匹配.;所以.+?现在匹配em
  • 模式中的>现在与输入中的>匹配。

关于否定的字符类和占有量词组合

请注意,在上述任何一种情况下,.+.+?必须回溯才能匹配>。这就是为什么<.++> 永远匹配<em>的原因,因为这是发生的事情:

  • 模式中的<与输入中的<匹配
  • 然后.++在输入中匹配尽可能多的.,并且将拥有此匹配
    • 它不会放过它匹配的任何东西! (因此“占有欲”)
    • 在这种情况下,.++能够匹配em>
  • 现在模式中的>永远不会匹配,因为任何>都会被.++吞噬
    • 由于它占有欲,.++不会通过回馈>
    • 来“合作”

至少有机会匹配的模式是<[^>]++>。与<em>匹配时:

  • 模式中的<与输入中的<匹配
  • 然后[^>]++在输入中占用[^>]所占数量(即>以外的任何内容)
    • 在这种情况下,它将占有em
  • 模式中的>现在可以与输入中的>匹配

尽可能实际,您应该避免在模式中使用.*? / .*.太灵活了,因为它匹配(差不多!)任何字符,这会导致不必要的回溯和/或匹配。

只要适用,您应使用否定字符类而不是.

regular-expressions.info

相关问题