我发现非贪婪的正则表达式匹配只是在锚定到前面而不是结束时变得非贪婪:
$ 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中进行了说明)。
答案 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$/
详细信息:
a
匹配1个字符(a
)。
.*?
匹配0个字符(空字符串)。
c
无法匹配。原路返回!.*?
匹配1个字符(b
)。
c
匹配1个字符(c
)。
$
无法匹配。原路返回!.*?
匹配2个字符(bc
)。
c
无法匹配。原路返回!.*?
匹配7个字符(bcabcab
)。
c
匹配1个字符(c
)。
$
匹配0个字符(空字符串)。匹配成功! "abcabcabc" = /a.*c$/
详细(对比):
a
匹配1个字符(a
)。
.*
匹配8个字符(abcabcabc
)。
c
无法匹配。原路返回!.*
匹配7个字符(abcabcab
)。
c
匹配1个字符(c
)。
$
匹配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
在这种情况下使用后三者将是低效且难以理解的,但它们将使用长于一个字符的边界。