【发布时间】:2011-01-19 01:36:01
【问题描述】:
这两个术语是什么意思?
【问题讨论】:
标签: regex regex-greedy non-greedy
这两个术语是什么意思?
【问题讨论】:
标签: regex regex-greedy non-greedy
Greedy 意味着您的表达式将匹配尽可能大的组,lazy 意味着它将匹配尽可能小的组。对于这个字符串:
abcdefghijklmc
还有这个表达式:
a.*c
贪婪匹配会匹配整个字符串,而惰性匹配只会匹配第一个abc。
【讨论】:
'Greedy' 表示匹配最长的字符串。
'Lazy' 表示匹配最短的可能字符串。
例如,贪婪的h.+l 匹配'hello' 中的'hell',但懒惰的h.+?l 匹配'hel'。
【讨论】:
h.+l 匹配'helolo' 中的'helol',但懒惰的h.+?l 匹配'hel'。
x? 表示 x 是可选的,但 +? 是不同的语法。这意味着停止寻找匹配的东西 - 惰性匹配。
? 表示可选,+? 表示懒惰。因此\+? 表示+ 是可选的。
常规中的标准量词 表达式是贪婪的,这意味着它们 尽可能匹配,只给予 根据需要返回以匹配 正则表达式的其余部分。
通过使用惰性量词, 表达式尝试最小匹配 首先。
【讨论】:
贪婪会尽可能多地消耗。在http://www.regular-expressions.info/repeat.html 中,我们看到了尝试将HTML 标记与<.+> 匹配的示例。假设您有以下内容:
<em>Hello World</em>
您可能认为<.+>(. 表示任何非换行符,+ 表示一个或多个)只会匹配<em> 和</em>,实际上它会非常贪婪,从第一个<到最后一个>。这意味着它将匹配 <em>Hello World</em> 而不是您想要的。
让它变得懒惰 (<.+?>) 可以防止这种情况发生。通过在+ 之后添加?,我们告诉它重复尽可能少的次数,所以它遇到的第一个> 是我们要停止匹配的地方。
我鼓励您下载 RegExr,这是一个可以帮助您探索正则表达式的好工具 - 我一直都在使用它。
【讨论】:
<[^>]+>regex101.com/r/lW0cY6/1
取自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
惰性 reg 表达式 em>:s.*?o 输出:stackoverflow
【讨论】:
re.match('(f)?(.*)', 'food').groups() 与re.match('(f)??(.*)', 'food').groups() 进行比较。在后者中,(f)?? 不会匹配前导的“f”,即使它可以匹配。因此,'f' 将与第二个 '.*' 捕获组匹配。我相信你可以用 '{n}?' 构造一个例子?也。诚然,这两个很少使用。
{n}? 等价于 {n}。见stackoverflow.com/questions/18006093/how-do-an-and-an-differ
尝试理解以下行为:
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 在评论中提到的那样。
什么是贪婪,什么是懒惰,请参考下面的例子。
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
【讨论】:
贪婪匹配。 正则表达式的默认行为是贪婪。这意味着它会尝试尽可能多地提取,直到它符合某种模式,即使较小的部分在语法上就足够了。
示例:
import re
text = "<body>Regex Greedy Matching Example </body>"
re.findall('<.*>', text)
#> ['<body>Regex Greedy Matching Example </body>']
它不是匹配直到第一次出现“>”,而是提取整个字符串。这是正则表达式的默认贪婪或“通吃”行为。
延迟匹配,另一方面,“尽可能少”。这可以通过在模式末尾添加? 来实现。
示例:
re.findall('<.*?>', text)
#> ['<body>', '</body>']
如果您只想检索第一个匹配项,请改用搜索方法。
re.search('<.*?>', text).group()
#> '<body>'
【讨论】:
贪婪意味着它会消耗你的模式,直到它们都不剩并且它不能再看下去了。
Lazy 会在遇到您请求的第一个模式时立即停止。
我经常遇到的一个常见示例是正则表达式([0-9]{2}\s*-\s*?[0-9]{7}) 的\s*-\s*?
第一个\s* 因为* 而被归类为贪婪,并且在遇到数字后会尽可能多地查找空格,然后查找破折号“-”。第二个\s*? 是懒惰的,因为*? 的存在意味着它会看起来是第一个空白字符并停在那里。
【讨论】:
\s 只能匹配一个空格,并且要求后面有 7 位数字。
最好的例子。细绳。 192.168.1.1 和一个贪婪的正则表达式 \b.+\b
您可能认为这会给您第一个八位字节,但实际上匹配整个字符串。为什么?因为.+ 是贪心的,贪心匹配匹配192.168.1.1 中的每个字符,直到它到达字符串的末尾。这是重要的一点!现在它开始一次回溯一个字符,直到找到第三个标记 (\b) 的匹配项。
如果字符串是一个 4GB 的文本文件和 192.168.1.1,那么您可以很容易地看到这种回溯将如何导致问题。
要使正则表达式不贪心(懒惰),请在贪心搜索后加上问号,例如
*?
??
+?
现在发生的是令牌 2 (+?) 找到匹配项,正则表达式沿字符移动,然后尝试下一个令牌 (\b) 而不是令牌 2 (+?)。所以它小心翼翼地爬行。
【讨论】:
如果它在那里,他们会全部拿走。
IRS 与此正则表达式匹配:.*
$50,000
这将匹配所有内容!
查看示例:Greedy-example
如果我要求退税,国税局突然变得不贪婪,他们使用这个量词:
(.{2,5}?)([0-9]*) 反对这个输入:$50,000
第一组是非需要的,只匹配$5——所以我得到了$5 50,000 美元输入的退款。他们不贪婪。他们尽可能地少。
请看这里:Non-greedy-example。
如果您尝试匹配表达式的某些部分,这一点就变得很重要。有时您不想匹配所有内容。
希望这个类比能帮助你记住!
【讨论】: