【问题标题】:Regex of a non-greedy match different behavior非贪婪匹配不同行为的正则表达式
【发布时间】:2016-12-06 01:52:34
【问题描述】:

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

$ 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 中进行了说明)。

【问题讨论】:

  • /(a.c*?)$/ 匹配 'abcabcabc' 中的最后一个 'abc'。由于您要锚定到最后,因此 c 应该是非贪婪的。
  • @AdityaJ.,不,你改变了“算法”。对于您的“解决方案”,即使没有*?,即/(a.c)$/,它仍然可以工作。不过感谢您的尝试。
  • 使用.*?,正则表达式引擎开始匹配量词允许的最小字符数——。然后引擎前进并尝试下一个令牌。这失败了,所以引擎回溯并扩展它的匹配。这个过程不断重复——正则表达式引擎前进、失败、回溯、再次扩展匹配、前进、失败……这是否定/a[^a]*c$/的例子

标签: regex perl go


【解决方案1】:
$ echo abcabcabc | perl -ne 'print $1 if /(a.*?c)$/'
abcabcabc
# what, non-greedy become greedy?

非贪婪意味着它会在当前位置匹配尽可能少的字符,这样整个模式就会匹配。

在位置a 匹配0 后,bcabcab 是最少.*? 可以匹配位置1,同时仍然满足模式的其余部分。

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

  1. 在位置 0,a 匹配 1 个字符 (a)。
    1. 在位置 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. 在位置 9,$ 匹配 0 个字符(空字符串)。匹配成功!

"abcabcabc" = /a.*c$/详细(对比):

  1. 在位置 0,a 匹配 1 个字符 (a)。
    1. 在位置 1,.* 匹配 8 个字符 (abcabcabc)。
      1. 在位置 9,c 匹配失败。原路返回!
    2. 在位置 1,.* 匹配 7 个字符 (abcabcab)。
      1. 在位置 8,c 匹配 1 个字符 (c)。
        1. 在位置 9,$ 匹配 0 个字符(空字符串)。匹配成功!

提示:避免使用两个非贪婪修饰符实例的模式。除非您将它们用作优化,否则它们很有可能匹配您不希望它们匹配的东西。这在这里是相关的,因为模式隐含地以 \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

在这种情况下使用后三个是低效且不可读的,但它们适用于超过一个字符的边界。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多