在开始说明贪心(Greedy)和懒惰(Lazy)之前,先解释规则表达式的量词符号(Quantifier Symbols),主要就下表6这个:
+---+-------------------------------------+
| | Quantifier Symbols |
+---+-------------------------------------+
| | 贪心法 | 懒惰 |
+---+-------------------------------------+
| 1 | * | *? | 匹配0次或者多次
| 2 | + | +? | 匹配1次或者多次
| 3 | ? | ?? | 匹配0次或者1次
| 4 | {n} | {n}? | 匹配正好n次
| 5 | {n,} | {n,}? | 匹配至少n次
| 6 | {n,m} | {n,m}? | 匹配n次到m次之间
+---+-------------------------------------+
简单的说:
- 贪心法,就是匹配最长的串,即一直往后匹配直至不能再满足为止。
- 懒惰法,就是匹配最短的串,即主要匹配上就停止。
举一个例子看两者的差异:
text := "abcabc"
fmt.Printf("%q\n", regexp.MustCompile(`ab.*c`).FindAllString(text, -1)) // ["abcabc"]
fmt.Printf("%q\n", regexp.MustCompile(`ab.*?c`).FindAllString(text, -1)) // ["abc" "abc"]
第一种是贪心法,找到"ab"之后一直往后匹配,直到最后一个"c",所以其输出结果就是"abcabc"。
第二种是懒惰法,找到"ab"之后一直往后匹配,碰到第一个"c"就停止,所以这个例子里面,能找到两个匹配的子串"abc"和"abc"。
其实第二种的懒惰法可以用另外一种写法:
fmt.Printf("%q\n", regexp.MustCompile(`ab[^c]*c`).FindAllString(text, -1))
就是在"ab"之后对"非-c"的字符实现贪心法匹配,然后再碰到"c"就停止,这样达到同样的结果。
参考资料:
Greedy and lazy quantifiers
这篇文件比较详细的介绍了贪心法和懒惰法的匹配规则。
不过从具体应用来看,一种需求往往会有多个表达式的写法,所以对于懒惰法的写法也可以用其他的规则表达式来代替,所以如果你实在搞不清楚懒惰法的用处,也可以不用,只要自己找到新的表达法就行。