backreference (反向引用)与 backtracking(回溯) 没有关系,它们是两个不同的概念(虽然从英文字面上看有类似之处,但翻译为中文还是宜将它们区分开来--这一点余晟老师是正确的)。
反向引用,指的是在正则表达式中通过 \1、\2 等元序列(或者说是引用变量)引用前面分组的匹配项,以匹配相同的内容。(参见分组、反向引用与编号或命名组)
回溯,指的是重复的限定符(+、* )在匹配模式时使用的一种回溯机制,或者说一种回吐机制(这是我个人的非正式说法)。
举个例子:比如在使用模式 ".*- 匹配字符串 "a-bc" 时,正则表达式引擎首先会匹配模式和字符串开始处的 ",然后模式中以限定符 * 限定的句点会匹配剩下的 a-bc"(因为句点匹配除换行符之外的任何字符,而且默认的重复限定符都是贪婪的,会重复尽可能多次 . 元字符)。此时字符串中已经没有可以匹配的字符了,但模式中还有 – 这个组件没有匹配。由于使用重复限定符的模式还有回溯机制,所以此时不能承认匹配失败,而是尝试开始回溯--也就是说此时引擎会逐个让出(give up)业已匹配的字符、首先是最后的 " 与模式中的 – 进行匹配,结果没有匹配;然后引擎再次让出字符 c 与 – 匹配,仍然没有匹配,继续让出字符 b,还是没有匹配。而当让出字符 – 时,结果匹配了。此时模式中的所有组件都成功匹配,整个模式也取得了匹配项--"a-。这个反向倒溯、回吐的过程就是正则表达式中的回溯。
当然,这是在默认情况下,如果使用非贪婪(或懒惰)匹配限定符,即将模式修改为 ".*?-,那么匹配过程就是:正则表达式引擎用模式中的第一个组件 " 匹配字符串初始的直接量字符 ",结果匹配;然后被 ? 限制的 * 限定符,将尽可能少地重复 . 元字符,因为 * 最少匹配零次,所以引擎首先会尝试重复 . 元字符零次,也就是直接用后面 – 匹配 a,结果当然不会匹配。但此时引擎不会就此甘休,而是会启动回溯机制,不过这时不是减少匹配字符,而是向前扩展式的“回溯”,即尝试重复一次 . 元字符,结果 . 元字符与 a 匹配,然后再用 – 匹配 a 后面的 -,结果匹配了。于是,非贪婪限定符在找到匹配项的前提下重复了尽量少的次数(1次),而且,模式中的所有组件都成功匹配,最终整个模式取得了匹配项--"a-。
显然,由于在默认情况下限定符为找到合适的匹配项都有可能要回溯,所以回溯存在占用资源的问题。而这个问题在使用嵌套的限定符时会变得非常突出。所谓嵌套的限定符,是指某个组中包含重复性的限定符,而这个组本身也应用了重复性限定符。因此,也就引出了占有式限定符(Possessive Quantifier)和最小化组(Atomic Group)的概念,这两个概念再谈吧,总之一句话说,成功就成功,失败就失败,不允许重复限定符启动回溯机制。
从以上分析可以看出,回溯与反向引用没有关系,至少是没有直接关系的。所以下面微软中文文档中的例子,虽然同时提到了反向引用和回溯,但只是强调一种可能性而已。
Nonbacktracking Lookahead and Lookbehind
Positive lookahead and lookbehind do not backtrack. That is, their contents are treated in the same way as the contents of a nonbacktracking (?> ) group.
Because lookahead and lookbehind are always zero-width, backtracking behavior is visible only when capturing groups appear within positive lookahead and lookbehind. For example, the expression (?=(a*))\1a will never find a match because group 1, which is defined within the lookahead, consumes as many “a” characters as there are, then \1a requires one more. Because the lookahead expression is not backtracked, the matching engine does not retry group 1 with fewer “a” characters.
For more on grouping, lookahead, and lookbehind constructs, see Grouping Constructs
我的中文译文是:
非回溯的向前查找及向后查找。
肯定式向前查找和向后查找不进行回溯。换句话说,它们的内容〔注1〕被作为一个非回溯(?>)组来处理。
由于向前查找和向后查找都是零宽度〔注2〕,因此只有当肯定式向前查找和向后查找中存在捕获组时回溯行为才是有可能发生的〔注3〕。例如,表达式 (?=(a*))\1a 永远不会找到匹配项,因为在向前查找中定义的组 1 会占有全部的字符 a,而 \1a 同样也需要匹配一个以上的字符 a。由于向前查找表达式是不进行回溯的,所以匹配引擎〔注4〕不会重新尝试让组 1 匹配更少的字符 a〔注5〕。
要了解有关分组、向前查找和向后查找的更多信息,请参考分组构造
注1:指向前查找或向后查找模式。
注2:即只匹配不返回结果,或者说匹配的是位置。
注3:指可能会在后面反向引用该捕获组时触发回溯--事实上不会发生。
注4:即正则表达式引擎。
注5:即不会(也不可能)进行回溯。





