引用的是内容不是模式
反向引用让模式回头引用前面某个捕获组实际匹配到的文本,而不是重新执行那段模式。写一个引用第 1 组的记号,意思是「这里必须出现与第 1 组完全相同的一串字符」,比较的是具体内容。
为什么强大又昂贵
这个特性让「前后必须一致」的约束可以被直接表达,例如成对引号、成对标签、重复词检测。代价是它打破了纯正则的理论边界,多数引擎因此无法使用自动机式优化,处理长输入时性能明显下降。
基本信息
| 模式内写法 | 反斜杠加组号;命名组用专门的引用语法 |
|---|---|
| 引用对象 | 前面捕获组实际匹配到的文本 |
| 大小写 | 默认区分大小写,开启忽略大小写后比较也随之放宽 |
| 支持情况 | PCRE、Python、Java、.NET、JavaScript 等支持;RE2、Go 标准库不支持 |
| 替换串引用 | 替换时引用的是另一套语法,与模式内反向引用不是一回事 |
| 未参与组 | 被引用的组未参与匹配时,多数引擎直接判定整体失败 |
典型使用场景
- 检测文本里重复出现的词,例如连续两处相同单词
- 匹配成对引号包起来的内容,确保首尾引号一致
- 匹配成对标签结构,闭合标签必须与开始标签同名
- 校验首尾同字符的定界格式,例如以特定符号包裹的字段
- 在替换中重排或去重,需要与替换引用配合使用
反向引用的写法
反向引用的写法
import re
re.search(r'\b(\w+)\s+\1\b', 'this is is a test') # 找出连续重复的词
re.search(r'(["\'])(.*?)\1', '"a"') # 首尾引号必须一致
re.search(r'<(h[1-6])>.*?</\1>', '<h2>x</h2>') # 闭合标签与开始标签同名
re.search(r'(?P<q>")\w+(?P=q)', '"ab"') # 命名分组的引用写法
re.search(r'(a)(b)\2\1', 'abba') # 多个引用可组合
re.sub(r'\b(\w+)\s+\1\b', r'\1', 'is is') # 替换掉重复的词两种引用的区别
| 场景 | 写法举例 | 含义 |
|---|---|---|
| 模式内反向引用 | 反斜杠加组号 | 此处必须出现与某组相同的内容 |
| 替换串引用 | 反斜杠加组号或美元符号加组号 | 把某组内容放进替换结果 |
| 命名组引用 | 按名字引用 | 可读性更好,适合组数多的模式 |
| 不支持引用的引擎 | RE2 一类 | 需改用两段式校验或程序内比较 |
反向引用会让引擎失去自动机式优化,长输入上可能出现明显延迟。在需要处理不可信长文本的路径上,应限制输入长度或改用程序内二次比较,避免成为性能短板。
跨语言移植时要先确认目标引擎是否支持反向引用。部分追求线性复杂度的引擎明确不支持该特性,模式会直接编译失败,此时需要改成先捕获再比较的两步方案。