非贪婪的正则表达匹配不同的行为

时间:2016-12-06 01:52:35

标签: regex perl go

我发现非贪婪的正则表达式匹配只是在锚定到前面而不是结束时变得非贪婪:

$ echo abcabcabc | perl -ne 'print $1 if /^(a.*c)/'
abcabcabc
# OK, greedy match

$ echo abcabcabc | perl -ne 'print $1 if /^(a.*?c)/'
abc
# YES! non-greedy match

现在看看这个,当锚定到最后:

$ echo abcabcabc | perl -ne 'print $1 if /(a.*c)$/'
abcabcabc
# OK, greedy match

$ echo abcabcabc | perl -ne 'print $1 if /(a.*?c)$/'
abcabcabc
# what, non-greedy become greedy?

为什么?怎么不像以前一样打印abc

(问题出现在我的Go代码中,但为了简单起见,在Perl中进行了说明)。

1 个答案:

答案 0 :(得分:7)

$ echo abcabcabc | perl -ne 'print $1 if /(a.*?c)$/'
abcabcabc
# what, non-greedy become greedy?

非贪婪意味着它会匹配当前位置的最少字符,以便整个模式匹配。

在位置a匹配0后,bcabcab在位置.*?上匹配的1最少,同时仍然可以满足其余模式。< / p>

"abcabcabc" = /a.*?c$/详细信息:

  1. 在pos 0,a匹配1个字符(a)。
    1. 在pos 1,.*?匹配0个字符(空字符串)。
      1. 在第1位,c无法匹配。原路返回!
    2. 在第1位,.*?匹配1个字符(b)。
      1. 在第2位,c匹配1个字符(c)。
        1. 在第3位,$无法匹配。原路返回!
    3. 在第1位,.*?匹配2个字符(bc)。
      1. 在第1位,c无法匹配。原路返回!
    4. ...
    5. 在第1位,.*?匹配7个字符(bcabcab)。
      1. 在第8位,c匹配1个字符(c)。
        1. 在pos 9,$匹配0个字符(空字符串)。匹配成功!
  2. "abcabcabc" = /a.*c$/详细(对比):

    1. 在pos 0,a匹配1个字符(a)。
      1. 在第1位,.*匹配8个字符(abcabcabc)。
        1. 在第9位,c无法匹配。原路返回!
      2. 在第1位,.*匹配7个字符(abcabcab)。
        1. 在第8位,c匹配1个字符(c)。
          1. 在pos 9,$匹配0个字符(空字符串)。匹配成功!
    2. 提示:避免使用两个非贪婪修饰符实例的模式。除非您将它们用作优化,否则它们很有可能匹配您不希望它们匹配的内容。这与此相关,因为模式隐含地以\G(?s:.*?)\K开头(除非由前导^\A\G取消。

      您想要的是以下之一:

      /a[^a]*c$/
      /a[^c]*c$/
      /a[^ac]*c$/
      

      您还可以使用以下方法之一:

      /a(?:(?!a).)c$/s
      /a(?:(?!c).)c$/s
      /a(?:(?!a|c).)c$/s
      

      在这种情况下使用后三者将是低效且难以理解的,但它们将使用长于一个字符的边界。