两个最基本的量词
星号表示前面的元素可以出现零次或多次,加号表示一次或多次。它们都是贪婪的:先尽量多取,后续部分匹配不上时再逐步退回。区别只在允许的最少次数:星号允许一个都不出现,所以它总能匹配成功;加号要求至少一个。
作用对象是谁
量词只作用于紧挨在它前面的那一个元素:可能是一个字符、一个字符类、一个分组、一个断言。写在分组后面就等于对整组重复,这也是把量词用在多字符结构上的唯一办法。
基本信息
| 最小次数 | 星号为 0,加号为 1 |
|---|---|
| 最大次数 | 两个都无上限,受引擎回溯次数与内存限制 |
| 默认风格 | 贪婪,先多后少 |
| 作用范围 | 仅紧邻其前的单个元素,分组后才作用整组 |
| 搭配建议 | 长度无约束的重复往往要配锚点或非贪婪,否则容易吃过头 |
典型使用场景
- 跳过数量不定的空白:空白类加星号是最常见的写法
- 匹配一行内的注释内容:注释符之后直到行尾的部分
- 校验一串重复结构,例如多段用分隔符连接的标识
- 提取 HTML 或日志片段,配非贪婪限制在最近的分隔符处
- 匹配可能为空的字段,此时必须用星号而不是加号
贪婪行为的观察
贪婪行为的观察
import re
re.findall(r'a*', 'aa b') # 星号可匹配空串,结果里会夹带空片段
re.findall(r'a+', 'aa b') # 加号要求至少一次,结果更干净
re.search(r'<b>.*</b>', '<b>x</b><b>y</b>') # 贪婪:一路吃到最后一个
re.search(r'<b>.*?</b>', '<b>x</b><b>y</b>') # 非贪婪:只取第一段
re.search(r'^(\s*)', ' x').group(1) # 配合分组把星号收益取出来
re.fullmatch(r'\d+', '12345') # 加号配全串匹配做纯数字校验量词选择对照
| 需求 | 写法 | 说明 |
|---|---|---|
| 允许不出现 | 星号 | 可匹配空串,替换时易产生多余结果 |
| 至少一次 | 加号 | 空串输入会失败,校验更严 |
| 次数固定范围 | 花括号写法 | 比堆叠星号更明确、更易读 |
| 未定长度但想取最短 | 星号加问号 | 变非贪婪,性能通常也更好 |
星号匹配空串这一特性会在全局替换和批量查找里制造大量零长度命中,很多语言的替换接口对此有专门说明。若不希望出现空匹配,先把量词换成加号,或给重复加上最小次数。
在 POSIX 基本正则里,加号不是量词而是普通字符,需要写反斜杠才生效;星号则一直是量词。跨工具搬模式时这一点最容易被忽略。