这两个术语是什么?


贪婪意味着你的表达式将匹配尽可能大的组,懒惰意味着它将匹配尽可能小的组。对于这个字符串:

abcdefghijklmc

这个表达式是:

a.*c

贪婪匹配将匹配整个字符串,而懒惰匹配将只匹配第一个abc。


'Greedy'表示匹配最长的字符串。

'Lazy'表示匹配最短的字符串。

例如,贪婪的h.+l匹配'hello'中的'hell',但懒惰的h.+?L和“hel”匹配。


来自正则表达式

regular中的标准量词 表达式是贪婪的,这意味着它们 尽可能多地匹配,只给予 回视需要进行匹配 正则表达式的剩余部分。 通过使用惰性量词,的 表达式尝试最小匹配 第一。


贪婪的人会尽可能多地消费。在http://www.regular-expressions.info/repeat.html中,我们看到了试图将HTML标记与<.+>匹配的示例。假设你有以下情况:

<em>Hello World</em>

你可能认为…+ >(。表示任何非换行符,+表示一个或多个)将只匹配<em>和</em>,而实际上它将非常贪婪,并从第一个<到最后一个>。这意味着它将匹配<em>Hello World</em>,而不是你想要的。

将其设置为惰性(<.+?>)将防止这种情况。通过添加?在+之后,我们告诉它重复尽可能少的次数,所以它遇到的第一个>就是我们想要停止匹配的地方。

我鼓励你下载RegExr,这是一个很好的工具,可以帮助你探索正则表达式——我一直在用它。


摘自www.regular-expressions.info

贪心:贪心量词首先尝试重复标记尽可能多的次数 尽可能,并逐渐放弃匹配,因为引擎返回寻找 一场全面的比赛。

惰性:惰性量词首先根据需要重复标记的次数,然后 随着引擎通过正则表达式返回到,逐渐扩展匹配 找到一个整体匹配。


Greedy quantifier Lazy quantifier Description
* *? Star Quantifier: 0 or more
+ +? Plus Quantifier: 1 or more
? ?? Optional Quantifier: 0 or 1
{n} {n}? Quantifier: exactly n
{n,} {n,}? Quantifier: n or more
{n,m} {n,m}? Quantifier: between n and m

加一个?给量词,使其不贪婪,即懒惰。

例子: 测试字符串:stackoverflow 贪心reg表达式:s.*o输出:stackoverflow Lazy reg表达式:s.*?O输出:stackoverflow


试着理解以下行为:

    var input = "0014.2";

Regex r1 = new Regex("\\d+.{0,1}\\d+");
Regex r2 = new Regex("\\d*.{0,1}\\d*");

Console.WriteLine(r1.Match(input).Value); // "0014.2"
Console.WriteLine(r2.Match(input).Value); // "0014.2"

input = " 0014.2";

Console.WriteLine(r1.Match(input).Value); // "0014.2"
Console.WriteLine(r2.Match(input).Value); // " 0014"

input = "  0014.2";

Console.WriteLine(r1.Match(input).Value); // "0014.2"
Console.WriteLine(r2.Match(input).Value); // ""

据我所知,大多数正则表达式引擎默认是贪婪的。在量词末尾添加问号将启用惰性匹配。

正如@Andre S在评论中提到的。

贪婪:继续搜索,直到条件不满足。 Lazy:当条件满足时停止搜索。

参考下面的例子,了解什么是贪婪的,什么是懒惰的。

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Test {
    public static void main(String args[]){
        String money = "100000000999";
        String greedyRegex = "100(0*)";
        Pattern pattern = Pattern.compile(greedyRegex);
        Matcher matcher = pattern.matcher(money);
        while(matcher.find()){
            System.out.println("I'm greedy and I want " + matcher.group() + " dollars. This is the most I can get.");
        }
        
        String lazyRegex = "100(0*?)";
        pattern = Pattern.compile(lazyRegex);
        matcher = pattern.matcher(money);
        while(matcher.find()){
            System.out.println("I'm too lazy to get so much money, only " + matcher.group() + " dollars is enough for me");
        }
    }
}

The result is:
I'm greedy and I want 100000000 dollars. This is the most I can get.

I'm too lazy to get so much money, only 100 dollars is enough for me

贪婪匹配。正则表达式的默认行为是贪婪的。这意味着它会尝试提取尽可能多的数据,直到它符合某个模式,即使在语法上只需要较小的部分就足够了。

例子:

import re
text = "<body>Regex Greedy Matching Example </body>"
re.findall('<.*>', text)
#> ['<body>Regex Greedy Matching Example </body>']

它提取了整个字符串,而不是直到' > '第一次出现才匹配。这是regex默认的贪婪或“全部拿走”行为。

另一方面,懒惰匹配“需要的越少越好”。这可以通过添加一个?在图案的最后。

例子:

re.findall('<.*?>', text)
#> ['<body>', '</body>']

如果只希望检索第一个匹配项,则使用search方法。

re.search('<.*?>', text).group()
#> '<body>'

来源:Python Regex Examples


贪婪意味着它将消耗你的模式,直到没有剩下的,它不能再看了。

Lazy会在遇到您请求的第一个模式时立即停止。

我经常遇到的一个常见的例子是\s*-\s*?([0-9]{2}\s*-\s*?[0-9]{7})

第一个\s*被归类为贪婪的,因为有*,它会在遇到数字后寻找尽可能多的空白,然后寻找破折号“-”。第二个s*在哪里?懒惰是因为*的存在吗?这意味着它将查看第一个空白字符并在那里停止。


最好用例子来说明。字符串。192.168.1.1和一个贪婪的正则表达式\b.+\b 你可能认为这会给你第一个八位元,但实际上是匹配整个字符串。为什么?因为。+是贪婪的,贪婪匹配匹配192.168.1.1中的每个字符,直到它到达字符串的末尾。这是最重要的一点!现在它开始一次回溯一个字符,直到找到与第三个标记(\b)匹配的字符。

如果字符串一个4GB文本文件和192.168.1.1在开始,你可以很容易地看到这个回溯会导致一个问题。

要使正则表达式非贪婪(懒惰),在你的贪婪搜索后放一个问号

*?
??
+?

现在发生的事情是令牌2(+?)找到一个匹配,regex沿着一个字符移动,然后尝试下一个令牌(\b),而不是令牌2(+?)。所以它小心翼翼地爬行着。


贪婪量词就像美国国税局

他们会尽量多拿。例如,匹配这个正则表达式:.*

The $50000

再见了,银行余额。

这里有一个例子:贪婪的例子

非贪婪量词——他们拿走的越少越好

要求退税:国税局突然变得不贪心了,退税越少越好:也就是说,他们用了这个量词:

(.{2,5}?)([0-9]*)与此输入:$50,000

第一组是不需要的,只匹配5美元-所以我从5万美元的输入中得到5美元的退款。

看这里:非贪婪的例子。

为什么我们需要贪婪和非贪婪?

如果你试图匹配一个表达式的某些部分,这就变得很重要。有时候你不想把所有的东西都搭配起来——越少越好。有时候你想要尽可能的匹配。仅此而已。

你可以使用上面链接中的例子。

(用来帮助你记忆的比喻)。


为了进一步说明懒惰,这里有一个例子,乍一看可能不太直观,但从Suganthan Madhavan Pillai的回答中解释了“逐渐扩大比赛”的想法。

input -> some.email@domain.com@
regex -> ^.*?@$

这个输入的Regex将有一个匹配。乍一看,有人可能会说LAZY match(".*?@")将在第一个@停止,之后它将检查输入字符串结束("$")。按照这个逻辑,有人会得出没有匹配的结论,因为输入字符串在第一个@之后没有结束。

但正如你所看到的,情况并非如此,即使我们使用非贪婪(懒惰模式)搜索,regex也会继续前进,直到它命中秒@并有一个MINIMAL匹配。