“贪婪”和“不情愿”正则表达式量词有什么区别?

2022-09-01 20:05:51

来自 Pattern javadocs:

Greedy quantifiers:
X?      X, once or not at all  
X*      X, zero or more times  
X+      X, one or more times  
X{n}    X, exactly n times  
X{n,}   X, at least n times  
X{n,m}  X, at least n but not more than m times

Reluctant quantifiers:
X??     X, once or not at all  
X*?     X, zero or more times  
X+?     X, one or more times  
X{n}?   X, exactly n times  
X{n,}?  X, at least n times  
X{n,m}? X, at least n but not more than m times

对他们所做的事情的描述是相同的...那么,有什么区别呢?

我真的很感激一些例子。

我用Java编码,但我听说这个概念对于大多数现代正则表达式实现都是一样的。


答案 1

贪婪的运算符总是试图“抓住”尽可能多的输入,而一个不情愿的量词将尽可能少地匹配输入,并且仍然创建匹配。

例:

"The red fox jumped over the red fence"
/(.*)red/ => \1 = "The red fox jumped over the "
/(.*?)red/ => \1 = "The "

"aaa"
/a?a*/ => \1 = "a", \2 = "aa"
/a??a*/ => \1 = "", \2 = "aaa"

"Mr. Doe, John"
/^(?:Mrs?.)?.*\b(.*)$/ => \1 = "John"
/^(?:Mrs?.)?.*?\b(.*)$/ => \1 = "Doe, John"

答案 2

这个链接,教程作者承认你的问题的精神:

乍一看,量词X?,X??和X?+做同样的事情,因为它们都承诺匹配“X,一次或根本不匹配”。有一些微妙的实现差异,将在本节末尾解释。

他们继续把例子放在一起,并提供解释:

贪婪的量词被认为是“贪婪的”,因为它们迫使匹配器在尝试第一次匹配之前读取或吃掉整个输入字符串。如果第一次匹配尝试(整个输入字符串)失败,则匹配器将回退输入字符串一个字符并重试,重复该过程,直到找到匹配项或没有更多字符可供退出。根据表达式中使用的量词,它将尝试匹配的最后一件事是 1 或 0 个字符。

然而,不情愿的量词采取相反的方法:它们从输入字符串的开头开始,然后不情愿地一次吃掉一个字符来寻找匹配项。他们尝试的最后一件事是整个输入字符串。

对于额外的功劳,所有格解释:

最后,所有格量词总是吃掉整个输入字符串,尝试一次(而且只尝试一次)进行匹配。与贪婪的量词不同,所有格量词永远不会退缩,即使这样做会让整体匹配成功。