regex 总览待审核
capture · backref · 两种「共用」

命名捕获 vs 反向引用:一个共用语法,一个共用文本

regex 语法速览页把命名组反向引用各一笔带过。它们常被混在一起,其实是两种不同的「共用」—— 分清楚,后面一堆困惑都解开了:

命名捕获 (?<x>…) = 共用 regex 语法 给某个捕获组起个名字 x;这个名字只是 \1 \2 数字下标的可读别名, 指向「pattern 里的那个组」。同一个名字之后能在 pattern 内 (\k<x>)、替换串里 ($<x>)、 结果对象里 (m.namedGroups.x) 到处复用——复用的是这个引用 / 标签,不增加任何匹配能力。 反向引用 \1 / \k<x> = 共用匹配到的字符串 它在匹配时不是「再跑一遍那段 pattern」,而是要求之前那个组实际吃到的那串文本,原封不动再出现一次。 复用的是运行时捕获到的文本——这让正则超出了「正则语言」,引擎得切到回溯。 一句话记牢:(\w+) \1 不是「一个词 + 空格 + 任意一个词」,而是「一个词 + 空格 + 同一个词」。 下面第二节那个对照框就在演示这件事。

命名捕获:一个名字,处处复用

把组起个名,匹配结果里就能按名字取字段(不用数 groups[3] 是第几个),替换时还能按名重排。 下面同时列出编号组 groups[]命名组 namedGroups{}——一眼看出 namedGroups.y 就是 groups[1],名字纯属别名。开 d 标志还能看到 indices.groups(各命名组的区间)。

d = 输出 indices · g = 替换全部
模板里 $<name> 按名插回

命中高亮

同一个名字 y 在四处指代同一个组:
定义(?<y>\d{4})-(?<m>\d{2})
pattern 内\k<y> ←反向引用 (见第 3 节)
替换串$<y>/$<m>
结果对象m.namedGroups.y

反向引用:共用的是「那串文本」,不是 pattern

最常见的误解:以为 \1 是「把第一个组的规则再匹配一次」。不是。它要求第一个组刚刚吃到的那串具体文本 原样再出现。下面同一串输入,左栏用 反向引用 (\w+) \1、右栏用两个独立组 (\w+) (\w+)—— 改输入框,看它们什么时候分道扬镳

i:GO go 里 GO 与 go 会算「同一串」吗?

(\w+) \1反向引用 — 第二个词必须 = 第一个词

(\w+) (\w+)两个独立组 — 不要求相等

对照结论:同样是 \w+,右栏「随便两个词」总能配上;左栏却只在两个词字面相同时才命中。 差别就在 \1 锁定的是左组捕获到的文本。这也是它的典型用途——查重复: 叠字 (\w)\1、连写的重复单词 \b(\w+)\s+\1\b flag 也管反向引用:输入 GO go、左栏 (\w+) \1——不开 flag 时✗(GOgo,逐字不等); 加上 i 就✓。原因是「同一串文本」要按当前的大小写折叠 (case folding) 来判等:开 iGOgo 折叠后相同,于是算「同一串」。换言之,反向引用比的不是死板的字节相等,而是在当前 flag 语义下的相等。 (点下面带 /i 的例子直接对比。)

组合:\k<name> —— 用名字做反向引用

把前两件事叠起来:反向引用也能按名字写,即 \k<name>。语义和 \1 完全一样 (要求同一串文本重现),只是把数字换成可读的名字。最经典的两个场景是配对:开闭引号必须同种、 HTML 开闭标签必须同名——「同种 / 同名」正是「共用同一串文本」。

命中高亮

📋 两种「共用」一张表对齐

维度命名捕获 (?<x>…)反向引用 \1 / \k<x>
复用的是什么一个名字 = 某个组的可读别名(指向 pattern 里的组)那个组实际匹配到的文本
作用在哪一层写 / 读层面:pattern、替换串 $<x>、结果 m.namedGroups.x匹配运行时:要求同一串文本再次出现
改变匹配能力吗 —— 纯别名,和编号组 \1 / groups[1] 等价 —— 超出正则语言 → 引擎切回溯
典型用途取字段 namedGroups.year、重排 $<m>/$<d>叠字 (\w)\1、重复词、配对引号 / 标签
注意分流:第 2、3 节凡是带 反向引用 的 pattern,结果栏都会标成回溯引擎; 第 1 节纯命名组(无反向引用 / lookaround)则走线性 Pike VM。这正印证了上表第三行—— 命名只是别名不改能力,反向引用才真的把正则推出了「正则语言」。详见 自研引擎那页的 AST 与字节码。

🔗 再深一点