Python命名分组用(?P<name>...)语法,groupdict()返回字典,group("name")取单值;re.sub()中须用g<name>引用;重复命名组仅3.6+支持,旧版需避免。

命名分组的语法和基本写法
Python 的 re 模块支持用 (?P<name>...)</name> 语法定义命名分组,比数字索引更直观、可维护性更强。它不是“高级技巧”,而是处理结构化文本时的标准做法。
常见错误是漏掉 P(写成 (?<name>...) 或 (?'name'...)),这会直接报错 re.error: unknown extension ?<。
-
(?P<year>d{4})</year>匹配四位数字并命名为year -
(?P<month>d{1,2})</month>匹配 1–2 位数字并命名为month - 整个模式如
r"(?P<year>d{4})-(?P<month>d{1,2})-(?P<day>d{1,2})"
提取结果:用 groupdict() 还是 group("name")?
匹配成功后,Match 对象提供两种方式取值:.groupdict() 返回字典,.group("name") 返回单个值。前者适合批量取所有命名组,后者适合只关心某一个字段。
注意:如果命名组未参与匹配(比如用了 ? 量词但没匹配上),.group("name") 会抛出 IndexError;而 .groupdict() 中对应键的值是 None —— 这点容易被忽略,尤其在解析不规则日志时。
立即学习“Python免费学习笔记(深入)”;
import re
text = "2023-04-15"
m = re.match(r"(?P<year>d{4})-(?P<month>d{1,2})-(?P<day>d{1,2})", text)
if m:
print(m.groupdict()) # {'year': '2023', 'month': '04', 'day': '15'}
print(m.group("year")) # '2023'
命名分组在 re.sub() 中怎么引用?
替换字符串里不能用 这种数字反向引用,必须改用 g<name> 或 g<1>(仍支持数字)。写成 或 $name 都会原样输出,不触发替换。
另一个坑是:如果正则里用了嵌套命名组或重复名称(Python 3.6+ 支持 (?P=name) 引用已命名组),替换时只认最外层定义的名称,且 g<name> 不支持跨分支引用。
- 正确:
re.sub(r"(\d{4})-(?P<month>\d{2})", r"Year:g<1>, Month:g<month>", s)" - 错误:
r"Year:, Month:$month"($month不生效)
性能和兼容性要注意什么?
命名分组本身几乎没有性能损失,但过度嵌套或大量使用 (?P=name) 回溯引用可能显著拖慢匹配速度,尤其在长文本中遇到失败匹配时。
Python 3.6+ 允许重复使用同一名称(通过 (?P=name)),但旧版本不支持,会报错 re.error: redefinition of group name。如果脚本需兼容 Python <3.6,就别在一个正则里多次定义同名分组,改用不同名 + 后续逻辑合并。
另外,re.fullmatch() 和 re.findall() 对命名分组的支持是一致的,但 re.findall() 默认只返回捕获组元组,要拿到字典得配合 re.finditer() + .groupdict()。


















