捕获组(Capturing Group)
圆括号 () 除了分组之外,还会"捕获"匹配到的内容,使你可以在结果中提取它:
import re m = re.search(r'(\d{4})-(\d{2})-(\d{2})', '生日:1990-06-15') print(m.group(0)) # '1990-06-15' 整个匹配 print(m.group(1)) # '1990' 第1组 print(m.group(2)) # '06' 第2组 print(m.group(3)) # '15' 第3组 print(m.groups()) # ('1990', '06', '15')
/(\d{4})-(\d{2})-(\d{2})/
生日:1990-06-15
紫色 = 第1组、橙色 = 第2组、绿色 = 第3组
非捕获组(Non-Capturing Group)
如果只需要分组(用于量词或选择),不需要捕获,使用 (?:...):
(?:https?|ftp)://\S+ # 匹配 URL,不捕获协议 (?:ab){3} # 匹配 "ababab",不创建捕获组
TIP养成使用
(?:...) 的习惯:不需要捕获时就用非捕获组,这样代码更清晰,引擎也可以省去存储捕获结果的开销。命名捕获组(Named Group)
用数字引用捕获组容易出错,命名捕获组让代码更可读:
# Python 语法:(?P<name>...) m = re.search( r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})', '2026-03-26' ) print(m.group('year')) # '2026' print(m.group('month')) # '03' print(m.groupdict()) # {'year': '2026', 'month': '03', 'day': '26'} # JavaScript ES2018 语法:(?<name>...) const m = '2026-03-26'.match(/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/) console.log(m.groups) // { year: '2026', month: '03', day: '26' }
反向引用(Backreference)
在同一正则中,可以用 \1、\2(Python: \1,JS: \1)引用前面捕获组匹配到的内容:
# 匹配重复单词(如 "the the") \b(\w+)\s+\1\b # 匹配对称的 HTML 标签 <(\w+)>.*?</\1>
/\b(\w+)\s+\1\b/g
the cat cat sat on the the the mat
检测重复单词——常用于文本校对
命名反向引用
# Python:\g<name> 或 (?P=name) re.sub(r'(?P<word>\w+)\s+(?P=word)', r'\g<word>', text) # JavaScript:\k<name> /(?<tag>\w+).*\k<tag>/
在替换中使用捕获组
捕获组在替换操作中大放异彩,可以重新组织匹配到的内容:
# 将 YYYY-MM-DD 转换为 DD/MM/YYYY result = re.sub( r'(\d{4})-(\d{2})-(\d{2})', r'\3/\2/\1', '今天是 2026-03-26' ) # → '今天是 26/03/2026' # JavaScript '2026-03-26'.replace(/(\d{4})-(\d{2})-(\d{2})/, '$3/$2/$1') // → '26/03/2026'
分组嵌套与编号规则
捕获组按左括号出现的顺序编号(从 1 开始):
(a(b(c))) # 1 2 3 编号 # group(1) → 'abc' # group(2) → 'bc' # group(3) → 'c'
常见应用场景
- 从日志中提取 IP、时间戳、错误码
- 解析 URL 各个组成部分(协议、域名、路径、参数)
- 日期格式转换(YYYY-MM-DD ↔ DD/MM/YYYY)
- 检测重复单词(文本校对)
- 匹配成对的 HTML/XML 标签
小结
()创建捕获组,匹配结果可以用\1引用或在替换中使用(?:...)是非捕获组,只分组不存储(?P<name>...)(Python)/(?<name>...)(JS)是命名捕获组,更具可读性- 反向引用
\1可以在同一正则中引用前面的捕获内容