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

递归中的量词

递归简介展示了 a(?R)?z 如何匹配 aaazzz量词 ? 使前一个标记可选。换句话说,它重复标记 0 次或 1 次。在 a(?R)?z 中,(?R) 由其后的 ? 使其可选。您可能想知道为什么正则表达式尝试了三次递归,而不是一次或根本没有尝试。

原因在于,在递归时,正则表达式引擎会重新开始尝试整个正则表达式。所有量词和备选方案的行为都好像递归之前的匹配过程从未发生过一样,除了引擎在字符串中前进。正则表达式引擎在退出递归时恢复所有量词和备选方案的状态,无论递归匹配成功还是失败。基本上,匹配过程正常继续,就好像递归从未发生过一样,除了引擎在字符串中前进。

如果你熟悉过程式编程语言,正则表达式递归基本上是一个递归函数调用,量词是函数中的局部变量。函数的每次递归都会得到自己的一组局部变量,这些变量不会影响堆栈中更高级别的递归中的相同局部变量,也不会受到这些局部变量的影响。递归中的量词在所有版本中都以这种方式工作,Boost 除外。

让我们看看 a(?R){3}z|q 的行为(Boost 除外)。最简单的可能匹配是 q,由正则表达式中的第二个备选方案找到。

第一个备选方案匹配的最简单匹配是 aqqqz。在 a 匹配之后,正则表达式引擎开始递归。a 无法匹配 q。引擎仍在递归中,尝试第二个备选方案。q 匹配 q。引擎以成功的匹配退出递归。引擎现在注意到量词 {3} 已成功重复一次。它需要再重复两次,因此引擎开始另一个递归。它再次匹配 q。在量词的第三次迭代中,第三次递归匹配 q。最后,z 匹配 z,并找到一个整体匹配。

此正则表达式不匹配 aqqzaqqqqzaqqz 失败,因为在量词的第三次迭代期间,递归无法匹配 zaqqqqz 失败,因为在 a(?R){3} 匹配 aqqq 后,z 无法匹配第四个 q

该正则表达式可以匹配更长的字符串,例如 aqaqqqzqz。对于此字符串,在量词的第二次迭代期间,递归匹配 aqqqz。由于每个递归分别跟踪量词,因此递归需要连续进行三次递归才能满足其量词的自身实例。这可能导致任意长的匹配,例如 aaaqqaqqqzzaqqqzqzqaqqaaqqqzqqzzz

Boost 如何处理递归中的量词

Boost 有自己关于量词如何在递归中工作的想法。递归仅在 Boost 中与其他风格相同,如果递归运算符根本没有量词,或者如果它具有 * 作为其量词。任何其他量词都可能导致 Boost 1.59 或更早版本与 Boost 1.60 及更高版本与其他正则表达式风格的匹配结果非常不同(或缺乏匹配结果)。Boost 1.60 试图修复 Boost 与其他风格之间的一些差异,但它只会导致不同的不兼容行为。

在 Boost 1.59 及更早版本中,递归量词在整个递归堆栈中同时计算迭代和递归。因此,Boost 1.59 中 a(?R){3}z|q 的可能匹配项包括 aaaazzzzaaaqzzzaaqqzzaaqzqzaqaqzzz。在所有这些匹配项中,递归和迭代的次数加起来为 3。没有其他版本会找到这些匹配项,因为它们需要在每次递归期间进行 3 次迭代。因此,其他版本可以匹配诸如 aaqqqzaqqqzaqqqzzaqqaqqqzz 之类的内容。Boost 1.59 仅会在这些字符串中匹配 aqqqz

Boost 1.60 尝试在每个递归级别迭代量词,就像其他版本一样,但执行不正确。使递归可选的任何量词都允许无限重复。因此,Boost 1.60 及更高版本将 a(?R)?za(?R)*z 视为相同。虽然这解决了 a(?R)?z 在 Boost 1.59 中无法完全匹配 aaazzz 的问题,但它也允许其他版本无法使用此正则表达式找到的匹配项,例如 aazazz。如果量词不是可选的,那么 Boost 1.60 只允许它在第一次递归期间匹配。因此,a(?R){3}z|q 只能匹配 qaqqqz

Boost 在递归量词方面的问题也会影响递归标记的父组上的量词。它们还会影响子例程调用上的量词和包含子例程调用(到具有量词的组的父组)的组上的量词。

递归中其他标记上的量词

正则表达式中其他标记上的量词在递归期间表现正常。它们在每次递归中分别跟踪其迭代。因此,a{2}(?R)z|q 匹配 aaqzaaaaqzzaaaaaaqzzz 等。a 必须在每次递归期间匹配两次。

这些量词位于递归内部,但不会重复递归本身,它们在 Boost 中可以正常工作。