快速入门
教程
工具和语言
示例
参考
书评
正则表达式教程
简介
目录
特殊字符
不可打印字符
正则表达式引擎内部
字符类
字符类减法
字符类交集
简写字符类
单词边界
交替
可选项目
重复
分组和捕获
反向引用
反向引用,第 2 部分
命名组
相对反向引用
分支重置组
自由间距和注释
Unicode
模式修饰符
原子分组
占有量词
前瞻和后顾
环视,第 2 部分
将文本排除在匹配之外
条件
平衡组
递归
子例程
无限递归
递归和量词
递归和捕获
递归和反向引用
递归和回溯
POSIX 方括号表达式
零长度匹配
继续匹配
本网站上的更多内容
简介
正则表达式快速入门
正则表达式教程
替换字符串教程
应用程序和语言
正则表达式示例
正则表达式参考
替换字符串参考
书评
可打印 PDF
关于本网站
RSS 源和博客
RegexBuddy—Better than a regular expression tutorial!

对失败组的反向引用

关于 反向引用 的上一主题适用于所有正则表达式风格,除了少数根本不支持反向引用的风格。当您开始做一些不符合“匹配先前捕获组匹配的文本”工作描述的事情时,不同风格的行为会有所不同。

引用未匹配的捕获组和根本未参与匹配的捕获组之间存在差异。正则表达式 (q?)b\1 匹配 bq? 是可选的,并且不匹配任何内容,导致 (q?) 成功匹配并捕获空内容。 b 匹配 b,并且 \1 成功匹配组捕获的空内容。

在大多数情况下,正则表达式 (q)?b\1 无法匹配 b(q) 完全无法匹配,因此该组根本无法捕获任何内容。由于整个组是可选的,因此引擎会继续匹配 b。引擎现在到达 \1,它引用了一个根本未参与匹配尝试的组。这会导致反向引用完全无法匹配,从而模拟组的结果。由于没有 ? 使 \1 可选,因此整体匹配尝试失败。

少数例外之一是 JavaScript。根据官方 ECMA 标准,对未参与捕获组的反向引用必须成功匹配空内容,就像对捕获空内容的参与组的反向引用一样。换句话说,在 JavaScript 中,(q?)b\1(q)?b\1 都匹配 bXPath 也以这种方式工作。

Dinkumware 对 std::regex 的实现处理反向引用,就像 JavaScript 处理所有支持反向引用的语法一样。 Boost 在 1.46 版之前也是如此。从 1.47 版开始,Boost 在使用 ECMAScript 语法时会使反向引用失败到未参与的组,但在使用基本和 grep 语法时仍允许它们成功匹配空内容。

对不存在的捕获组的反向引用

对不存在的组的反向引用,例如 (one)\7,在大多数正则表达式风格中都是一个错误。不过也有例外。JavaScript\1\7 视为 八进制转义,当正则表达式中的捕获组少于反斜杠后的数字时。\8\9 是错误的,因为 8 和 9 不是有效的八进制数字。

Java 将对不存在的组的反向引用视为对存在但从未参与匹配的组的反向引用。它们不是错误,但根本不匹配任何内容。

.NET 稍微复杂一些。.NET 支持个位数和两位数反向引用以及不带前导零的两位数八进制转义。反向引用优先于八进制转义。因此,在捕获组少于 12 个的正则表达式中,\12 是换行符(八进制 12 = 十进制 10)。在捕获组为 12 个或更多个的正则表达式中,它将是对第 12 个组的反向引用。.NET 不支持个位数八进制转义。因此,在捕获组少于 7 个的正则表达式中,\7 是一个错误。

前向引用

包括 JGsoft.NETJavaPerlPCREPHPDelphiRuby 在内的许多现代正则表达式风格允许前向引用。它们允许你使用对正则表达式中稍后出现的组的反向引用。前向引用显然只有在它们位于重复组内时才有用。然后,在某些情况下,正则表达式引擎可以在组已经匹配后评估反向引用。在尝试组之前,反向引用会像对失败组的反向引用一样失败。

如果支持前向引用,正则表达式 (\2two|(one))+ 将匹配 oneonetwo。在字符串的开头,\2 失败。尝试另一个 备选方案one 由第二个捕获组匹配,随后由第一个组匹配。然后重复第一个组。这一次,\2 匹配由第二个组捕获的 one。然后 two 匹配 two。通过两次重复第一个组,正则表达式匹配了整个主题字符串。

JavaScript 不支持前向引用,但不会将它们视为错误。在 JavaScript 中,前向引用始终找到零长度匹配,就像 JavaScript 中对非参与组的反向引用一样。由于这并不是特别有用,XRegExp 将它们视为错误。在 std::regexBoostPythonTclVBScript 中,前向引用是一个错误。

嵌套引用

嵌套引用是捕获组内部的反向引用,它引用了它本身。与前向引用一样,嵌套引用仅在它们位于重复组内时才有用,如 (\1two|(one))+。当支持嵌套引用时,此正则表达式也匹配 oneonetwo。在字符串的开头,\1 失败。尝试另一个 备选方案one 由第二个捕获组匹配,随后由第一个组匹配。然后重复第一个组。这一次,\1 匹配第一个组的最后一次迭代捕获的 one。正则表达式引擎重新进入第一个组并不重要。当组之前退出时,组匹配的文本已存储到反向引用中。然后 two 匹配 two。通过两次重复第一个组,正则表达式匹配了整个主题字符串。如果您在匹配后从捕获组中检索文本,第一个组将存储 onetwo,而第二个组将捕获字符串中 one 的第一次出现。

所有 JGsoft.NETJavaPerlVBScript 风格都支持嵌套引用。PCRE 也支持,但存在回溯到带有嵌套反向引用的捕获组的错误。PCRE 8.01 没有修复错误,而是通过强制带有嵌套引用的捕获组为 原子来解决这些错误。因此,在 PCRE 中,(\1two|(one))+(?>(\1two|(one)))+ 相同。这会影响基于 PCRE 的正则表达式引擎的语言,例如 PHPDelphiR

JavaScriptRuby 不支持嵌套引用,而是将它们视为对非参与组的回引,而不是错误。在 JavaScript 中,这意味着它们始终匹配一个零长度字符串,而在 Ruby 中,它们始终无法匹配。在 std::regexBoostPythonTcl 中,嵌套引用是一个错误。