量词与贪婪模式:掌握匹配的“量”与“度”

正则里有个很实在的概念——量词。说白了,就是告诉引擎“前面的东西要出现几次”。

我刚开始学的时候,觉得这东西太简单了。不就是星号、加号、问号吗?直到在一次日志解析项目里,被贪婪匹配坑得体无完肤……嗯,从那以后我才真正重视起来。

量词分两种性格:贪婪和懒惰。默认都是贪婪的,这容易出问题。咱们得搞明白它们是怎么工作的。

基础量词一览

先列个表,把常用的量词看清楚。你想想看,这些符号你肯定见过,但用对了吗?

量词 含义 等价形式
* 零次或多次 {0,}
+ 一次或多次 {1,}
? 零次或一次 {0,1}
{n} 恰好 n 次 固定次数
{n,} 至少 n 次 下限固定
{n,m} n 到 m 次 区间范围

我个人习惯:能用 {n,m} 的地方,尽量不用 * 或 +。显式写清楚范围,代码可读性高很多,也少出bug。

贪婪匹配:多拿多占

默认情况下,所有量词都是贪婪的。它会尽可能多地匹配字符。

看个例子:

文本:<div>内容1</div><div>内容2</div>
正则:<.*>
匹配结果:<div>内容1</div><div>内容2</div>

为什么匹配了整行?因为 .* 的贪婪本性,它会一直吞到最后一个 > 才停下。

我遇到过这种情况:写爬虫提取HTML标签时,用了 <.*>,结果把整个页面内容都匹配进去了。排查半天才发现是贪婪搞的鬼。

我曾经吃过的大亏:用 .* 匹配多行文本,没想到它不匹配换行符。后来改成 [\s\S]* 才解决问题。记住,. 默认不匹配 \n。

懒惰匹配:够用就行

在量词后面加个 ?,它就变懒惰了。能少匹配就少匹配。

还是刚才的例子:

文本:<div>内容1</div><div>内容2</div>
正则:<.*?>
匹配结果:<div>

看到了吗?.*? 在遇到第一个 > 就停了。这才是我们想要的效果。

为什么会这样?懒惰匹配每次扩展一个字符,发现满足条件就立刻返回。贪婪则相反,先吞下全部,再一个个吐出来检查。

核心记忆点:

  • 贪婪:能拿100个,绝不拿99个
  • 懒惰:给1个就要,绝不多拿

各种懒惰量词对照

懒惰量词就是在原有量词后面加 ?。我来列个表,一目了然:

贪婪版本 懒惰版本 含义
* *? 尽可能少地匹配零次或多次
+ +? 尽可能少地匹配一次或多次
? ?? 尽可能少地匹配零次或一次
{n,} {n,}? 尽可能少地匹配至少 n 次
{n,m} {n,m}? 尽可能少地匹配 n 到 m 次

你想想看,?? 这个写法挺有意思的。两个问号叠一起,第一个是量词,第二个是懒惰开关。记住这个规律就忘不了。

实战对比:文本提取的坑

来看一个常见的场景:从键值对文本中提取值。

文本:name=张三&age=25&city=北京
贪婪提取:name=(.*)&
匹配结果:name=张三&age=25&city=

用贪婪匹配,结果把从第一个 = 到最后一个 & 之间的内容全吞了。显然不对。

改成懒惰试试:

正则:name=(.*?)&
匹配结果:name=张三

正确!.*? 在遇到第一个 & 就停下了。

我建议:在提取结构化文本(如URL参数、JSON片段、XML标签)时,优先考虑懒惰匹配。不确定的时候,先用懒惰试,大概率是对的。

性能小贴士:别滥用懒惰

有一点要注意:懒惰匹配不一定比贪婪快。引擎需要频繁回溯,反复尝试。

场景不同,选择不同:

  • 提取短内容:懒惰更直观,不容易出错
  • 匹配长文本结尾:贪婪反而更高效,因为它一次到位
  • 多层嵌套结构:都不好用,考虑用递归匹配或解析器

知识体系:量词与模式选择

下面这张图,帮你梳理清楚量词的核心逻辑:

量词与贪婪模式知识体系 量词核心 基础量词 * 零次或多次 + 一次或多次 ? 零次或一次 {n,m} 区间范围 贪婪模式(默认) 尽可能多匹配 从右向左回溯 懒惰模式(加?) 尽可能少匹配 从左向右推进 贪婪 vs 懒惰对比 贪婪:匹配 <.*> → 整行 懒惰:匹配 <.*?> → 首个标签 本质:回溯方向不同 实战选择建议 提取短内容 → 懒惰 匹配尾部 → 贪婪 嵌套结构 → 考虑解析器 核心原则:明确需求 → 选择量词 → 确定模式 → 验证结果

避坑指南:量词使用三原则

总结几条实战经验,都是我踩过的坑:

  1. 明确边界:写量词前,确认你要匹配的内容边界在哪里。前后锚点(^、$、\b)能帮你精确定位。
  2. 能用具体就不用模糊:如果知道要匹配3个数字,写 \d{3} 比 \d+ 好一万倍。
  3. 测试懒惰:不确定用贪婪还是懒惰?先用懒惰版测试。大部分内容提取场景,懒惰更符合直觉。

最后分享一个经验:我每次写完正则,都会用最短和最长两种文本测试。短的看它会不会漏,长的看它会不会吞。这样能快速发现贪婪/懒惰的问题。