编号是怎么分配的
捕获组编号按左括号出现的先后顺序逐个数,第一个左括号是第 1 组,第二个是第 2 组,与括号何时结束无关。嵌套时外层括号先出现,所以外层编号一定小于内层。
谁不占编号
只有真正捕获的括号才占用编号:非捕获分组不占,单纯用于包裹的写法若不带捕获语义也不占;而断言内部的捕获括号在多数引擎里照样占编号,这是组号突然对不上的常见原因。
基本信息
| 第 0 组 | 整个匹配内容,由引擎固定提供 |
|---|---|
| 计数方式 | 按左括号在模式中出现的先后顺序 |
| 嵌套顺序 | 外层先计,内层后计 |
| 不占编号 | 非捕获分组不参与编号 |
| 占编号的特例 | 断言内部若使用捕获括号,会正常占用编号(视引擎实现) |
| 命名分组 | 多数引擎给命名分组同时保留数字编号与名字两种访问方式 |
典型使用场景
- 替换字符串中使用组引用进行字段重排
- 解析多层结构:外层捕获整体、内层分别捕获各段
- 排查替换结果错位问题,先数清模式里有多少个捕获括号
- 重构模式时评估插入新括号对既有引用的影响
- 为可读性把数字编号换成命名分组
编号顺序演示
编号顺序演示
import re
# 外层先编号,内层后编号
m = re.search(r'((\d{4})-(\d{2}))-(\d{2})', '2026-10-17')
print(m.group(1)) # 外层:整段日期主体
print(m.group(2)) # 内层:年份
print(m.group(3)) # 内层:月份
print(m.group(4)) # 最后一个括号:日
re.search(r'(?:x)(y)', 'xy').group(1) # 非捕获分组不占编号,y 是第 1 组
re.sub(r'(a)(b)', r'\2\1', 'ab') # 替换时按编号重排内容替换引用写法对照
| 环境 | 引用第 1 组 | 注意点 |
|---|---|---|
| Python 替换串 | 反斜杠加 1,或命名写法 | 反斜杠在字符串里需写成原始字符串 |
| JavaScript 替换串 | 美元符号加 1 | 两位数字会被当作两位组号 |
| Java 替换串 | 美元符号加 1 | 组号回引用与模式内引用写法不同 |
| sed 与 awk | 反斜杠加 1 | 需注意 shell 对反斜杠的处理 |
引用组号时如果是两位数字,紧跟其后的数字可能被一起当作组号解析。想引用第 1 组再接一个数字,应使用花括号包裹或命名引用写法把组号边界写清楚。
组号与读取方式并非完全通用:有的引擎在同时存在命名与匿名分组时编号规则有额外约定。跨语言移植模式时,组号相关的替换逻辑建议逐条验证,不要照抄。