1. 贪婪模式和非贪婪模式
在正则表达式中,贪婪模式和非贪婪模式的区别在于匹配字符时的 “贪心程度”。这两种模式主要影响重复元字符(如 *、+、?、{n,})的行为。
核心区别
| 模式 | 语法 | 匹配逻辑 |
|---|---|---|
| 贪婪 | .* | 尽可能多地匹配字符(直到无法匹配为止) |
| 非贪婪 | .*? | 尽可能少地匹配字符(一旦匹配就停止) |
深入解释
1. 贪婪模式(默认行为)
-
语法:
*、+、?、{n,}(无后缀)。 -
逻辑:从当前位置开始,尽可能多地匹配字符,直到无法继续匹配为止。
-
示例:
正则a.*c匹配a和c之间的任意字符(贪婪模式):plaintext
输入:ababc 匹配:ababc(最长可能的字符串)解释:
.*会先匹配整个babc,但由于末尾必须是c,因此最终匹配ababc。
2. 非贪婪模式(懒惰匹配)
-
语法:
*?、+?、??、{n,}?(添加?后缀)。 -
逻辑:从当前位置开始,尽可能少地匹配字符,一旦满足后续模式就立即停止。
-
示例:
正则a.*?c匹配a和c之间的任意字符(非贪婪模式):plaintext
输入:ababc 匹配:abc(最短可能的字符串)解释:
.*?先匹配空字符串,但后续需要c,因此逐步扩展匹配到ab,直到遇到第一个c为止。
实战对比
场景 1:提取 HTML 标签内容
- 输入:
<p>Hello</p><p>World</p> - 贪婪模式(正则:
<p>(.*)</p>):
匹配结果:<p>Hello</p><p>World</p>
问题:.*会吞掉中间的</p><p>,导致匹配整个字符串。 - 非贪婪模式(正则:
<p>(.*?)</p>):
匹配结果 1:<p>Hello</p>
匹配结果 2:<p>World</p>
正确提取两个标签的内容。
场景 2:提取引号内的内容
- 输入:
"apple" "banana" - 贪婪模式(正则:
"(.*)"):
匹配结果:"apple" "banana"
问题:.*匹配到最后一个引号,导致跨越多组内容。 - 非贪婪模式(正则:
"(.*?)"):
匹配结果 1:"apple"
匹配结果 2:"banana"
正确提取每组引号内的内容。
何时用哪种模式?
- 贪婪模式:当需要匹配最长的可能字符串时(如提取整个 HTML 块)。
- 非贪婪模式:当需要匹配最短的可能字符串时(如分割多个子串、提取特定标记内的内容)。
总结
- 贪婪模式:
.*像 “贪吃蛇”,尽可能多吃字符,直到满足整个正则。 - 非贪婪模式:
.*?像 “谨慎的食客”,吃到第一个满足条件的位置就停下。