在正则表达式中,“懒惰”和“贪婪”是什么意思?


Answers:


643

贪婪将消耗尽可能多的东西。从http://www.regular-expressions.info/repeat.html中,我们看到了尝试将HTML标签与匹配的示例<.+>。假设您具有以下条件:

<em>Hello World</em>

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

使其变得懒惰(<.+?>)可以防止这种情况。通过在?之后添加+,我们告诉它重复的次数越少越好,因此>它遇到的第一个就是我们要停止匹配的位置。

我鼓励您下载RegExr,这是个很棒的工具,可以帮助您探索正则表达式-我一直都在使用它。


2
因此,如果您使用greedy,您将有3个匹配项(1个元素+ 2个标签)还是只有1个匹配项(1个元素)?
ajsie 2010年

10
从第一个<到最后一个>结束,它将只匹配1次。
桑普森

3
但是使其变得懒惰将匹配两次,为我们提供了开始和结束标签,而忽略了中间的文本(因为它不适合表达式)。
桑普森

我一直使用的另一个出色工具:debuggex.com它也具有“嵌入StackOverflow”功能。
罗恩·范·德·海登2014年

8
只是要补充说,还有一种贪婪的方式可以解决此问题:<[^>]+> regex101.com/r/lW0cY6/1
alanbuchanan 2015年

301

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

“惰性”表示匹配最短的字符串。

例如,贪婪h.+l匹配'hell'中,'hello'而懒惰h.+?l匹配中'hel'


96
辉煌,那么懒惰会在满足条件l后立即停止,但是贪婪的意思是只有在不再满足条件l后它才会停止?
Andrew S

3
对于所有阅读该文章的人:贪婪或惰性的量词本身都不匹配最长/最短的子字符串。您将不得不使用经过调节的贪婪令牌,或者使用非正则表达式方法。
WiktorStribiżew16年

3
@AndrewS在示例中不要被double ll所迷惑。相当懒惰将匹配尽可能短的子字符串,而贪婪将匹配尽可能长的子字符串。贪婪的h.+l比赛'helol''helolo'但懒惰的h.+?l比赛'hel'
v.shashenko '17

3
@FloatingRock:编号。x?手段x是可选的,但+?语法不同。这意味着不要再寻找匹配的东西-惰性匹配。
slebetman '17

1
@FloatingRock:关于如何区分不同的语法,简单:?表示可选,+?表示惰性。因此,\+?手段+是可选的。
slebetman '17

113
+-------------------+-----------------+------------------------------+
| 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  |
+-------------------+-----------------+------------------------------+

添加一个?使量词变得不贪心即懒惰。

实施例:
测试字符串:计算器
贪婪reg表达式s.*o输出:stackoverflo瓦特
懒惰reg表达式s.*?o输出:stacko verflow


2
不是 ??相当于 ?。同样,{n}是吗?等效于{n}
编号945

5
@BreakingBenjamin:不?? 不等同于?,当它选择返回0或1次出现时,将选择0(惰性)替代项。要看到其中的差别,比较re.match('(f)?(.*)', 'food').groups()re.match('(f)??(.*)', 'food').groups()。在后者中,(f)??即使可以,也不会匹配前导“ f”。因此,“ f”将与第二个“。*”捕获组匹配。我确定您可以使用'{n}?太。诚然,这两个都是很少使用的。
smci

55

贪婪表示您的表达式将匹配尽可能大的组,惰性表示您的表达式将匹配最小的组。对于此字符串:

abcdefghijklmc

这个表达式:

a.*c

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


16

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

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

  • 贪婪:继续搜索,直到不满足条件为止。
  • 惰性:条件满足后,停止搜索。

关于贪婪和懒惰,请参考以下示例。

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 greeedy 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");
        }
    }
}


结果是:

I'm greeedy 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


6

正则表达式

正则表达式中的标准量词是贪婪的,这意味着它们尽可能地匹配,只返回必要的值以匹配正则表达式的其余部分。

通过使用惰性量词,表达式首先尝试最小匹配。


4

贪婪的匹配。正则表达式的默认行为是贪婪。这意味着即使语法上较小的部分,它也会尝试尽可能多地提取直到符合模式为止。

例:

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

它没有提取匹配到第一次出现的'>',而是提取了整个字符串。这是正则表达式的默认贪婪或“全部使用”行为。

另一方面,惰性匹配 “花最少的钱 ”。这可以通过?在模式的末尾添加a来实现。

例:

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

如果只想检索第一个匹配项,请改用搜索方法。

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

来源:Python Regex示例


3

贪婪意味着它将消耗您的模式,直到没有剩余的模式,而且看起来将不再。

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

我经常遇到的一个常见示例是\s*-\s*?正则表达式([0-9]{2}\s*-\s*?[0-9]{7})

第一个\s*被归类为贪婪的原因是*,遇到数字后,它将查找尽可能多的空格,然后查找连字符“-”。由于第二个字符\s*?的存在,第二个*?字符是懒惰的,这意味着它将看起来第一个空白字符并就此停止。


3

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

如果字符串开头是一个4GB的文本文件和192.168.1.1,则可以很容易地看到这种回溯将如何引起问题。

为了使正则表达式变得非贪婪(懒惰),请在贪婪搜索之后打一个问号,例如

*?
??
+?

现在发生的是令牌2(+?)找到一个匹配项,正则表达式沿着字符移动,然后尝试下一个令牌(\b)而不是令牌2(+?)。因此它会小心翼翼地爬行。


0

贪婪的量词就像是IRS / ATO:它们会尽其所能:

如果在那里,他们会来接走。他们将全部拿走:

例如,IRS与此正则表达式匹配: .*

$50,000 -国税局会全力以赴。那些贪婪的.*{4}?ERS

参见示例:regexr.com/4t27f

非贪婪量词-他们花的时间越少越好

另一方面,如果我要求退税,美国国税局突然变得不贪心,他们使用此量词:

(.{2}?)([0-9]*)反对这种表达方式:$50,000第一组是非个性化的,只匹配$5–因此我得到了$5退款。其余的由山姆大叔带走,浪费了。

参见此处:非贪婪示例

何必呢?

如果您要匹配表达式的某些部分,则变得很重要。有时您不想匹配所有内容。


-3

尝试了解以下行为:

    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); // ""
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.