捕获组与命名组:$1 和 $<name> 怎么对应
捕获组的编号规则只有一句:按左括号出现的顺序,从 1 开始。嵌套时外层先编号,因为它先出现。搞不清编号时,数左括号的位置比数右括号可靠。
编号怎么数
(\d{4})-(\d{2})-(\d{2})
三个组依次是 1、2、3。$1 是年、$2 是月、$3 是日。
嵌套时:
((\d{4})-(\d{2}))
外层 (…) 是第 1 组,里面的 (\d{4}) 是第 2 组,(\d{2}) 是第 3 组。因为外层左括号先出现。
非捕获组为什么有用
(?:…) 只分组不捕获,不占编号。当你想用括号表达「这几个字符作为一个整体重复」,但又不想让编号错位时用它:
(?:ab)+
如果写成 (ab)+,每多一个这样的分组,后面所有 $n 的编号都会往后挪一位——这是「改了一处正则,替换结果全乱」的常见原因。
命名组
(?<year>\d{4}) 定义名为 year 的组,替换时写 $<year>。工具会在结果列表里按名字列出每个命名组捕获的内容。
命名组的好处是抗改动:在它前面插入一个新分组,编号会变,名字不会。所以规则复杂时优先用命名组。
命名组的名字只能是字母、数字、下划线,且不能以数字开头。
「未参与匹配」与「匹配到空」的区别
这两件事看起来一样,实际完全不同:
- 未参与匹配:该组所在的分支没走到,值为
undefined。 - 匹配到空字符串:走过了,只是捕获内容为空,值为
""。
结果列表把未参与的组显示为空,方便区分。写替换逻辑时这个区别很关键:undefined 该保留原值,"" 该替换成空。
上面这些都不用装软件,也不用注册:打开页面就能用。
打开正则表达式测试器 →常见问题
最多能有多少个捕获组?
JavaScript 引擎没有硬性上限,但组数多了可读性会崩。超过五六个组建议改用命名组,或拆成多次匹配。
为什么 $1 替换后是空的?
一是组没参与匹配(分支没走到),二是编号数错了。先看结果列表里该组的实际值,再确认编号是否被新加的分组挤位。
命名组和编号组能混用吗?
能。命名组同时也有编号(按左括号顺序),所以 $1 与 $<name> 都能引用同一个组。