我正在尝试从多个来源研究正则表达式,但是遇到了关于回溯的困惑,因为一个定义了回溯,这意味着正则表达式引擎无法匹配模式时的状态,因此回溯到位置匹配第一个原子的位置,例如,要匹配cat
中的He captured a catfish for his cat
,引擎将按照以下步骤进行操作:
c
,直到与c
中的captured
匹配为止a
相同t
与p
匹配c
中captured
之后重设位置,因为它知道在这一点之前不会发生匹配。因此,在所有没有量词的情况下,引擎都将重置整个模式,以尝试从不同位置再次进行匹配。
另一个人将回溯定义为使用.*
之类的量词的状态,因此正则表达式引擎将匹配完整的文本,这将使其失败,因此它逐个回溯直到匹配发生。我认为这些不一样。
如here所述:
正则表达式匹配的基本特征涉及称为回溯的概念。
所有正则表达式量词(*,*?,+,+ ?、 {n,m}和{n,m})都使用(需要时)。要使正则表达式匹配,整个正则表达式必须匹配,而不仅仅是部分匹配。因此,如果包含量词的模式的开头成功而导致模式中的后续部分失败,则匹配引擎将备份并重新计算开头部分,这就是为什么将其称为回溯的原因。
这意味着像([A-Z][A-Z0-9]*)\b[^>]*>.*<\/\1>
这样与Testing <B><I>bold italic</I></B> text.
匹配的模式将像这样工作:
<B>
.*
,后者将匹配到字符串的末尾。<
,但是它已经到达末尾,因此它将逐个回溯一个字符,直到匹配为止。与第一个cat
示例相反,该示例将引擎完全重置为第一个原子,然后从与第一个原子匹配的位置重新开始。
但是在另一种情况下,如果我在?
之后添加.*
,则正则表达式会跳过此原子.*?
,尝试匹配其余字符,但是如果不匹配,它会退回到{{ 1}}进行匹配,直到出现.
,然后在其后开始匹配原子。
我认为这里有多个定义,任何人都可以解释这些情况中的哪个正在回溯。
答案 0 :(得分:1)
让我们检查一些回溯定义。
“ NFA引擎的本质是:它考虑了每个子表达式或 组件,并在需要时在两个同样可行的组件之间做出决定 选项,它会选择一个并记住另一个,以便在需要时返回。如果 尝试的选项成功,而其他正则表达式也成功,您就是 比赛结束。如果正则表达式其余部分中的任何内容最终导致 失败,正则表达式引擎知道它可以回溯到选择选项的位置, 可以尝试其他比赛来继续比赛。这样,它最终会尝试所有 正则表达式的可能排列(或至少根据需要排列,直到匹配 找到)。” Mastering Regular Expressions Powerful Techniques for Perl and Other Tools, Jeffrey E. F. Friedl, p.102
另一个:
”当正则表达式包含可选的量词或替代结构时,输入字符串的计算不再是线性的。使用NFA引擎进行模式匹配由正则表达式中的语言元素而不是要匹配的字符驱动因此,正则表达式引擎会尝试完全匹配可选或替代子表达式。当它前进到子表达式中的下一个语言元素并且匹配不成功时,正则表达式引擎可以放弃其成功匹配的一部分,并且为了将正则表达式作为一个整体与输入字符串进行匹配,返回到较早的保存状态。返回到先前的保存状态以查找匹配项的过程是被称为回溯”。 (Backtracking in Regular Expressions, Microsoft docs)
又一个:
”要使正则表达式匹配,整个正则表达式必须匹配,而不仅仅是部分匹配。因此,如果包含量词的模式的开头成功而导致模式中的后续部分失败,则匹配引擎备份并重新计算开始部分,这就是为什么将其称为回溯。” (source)
回溯的中心部分似乎是将“返回”过程返回到较早的状态,以便重新评估(重新匹配)字符串以使整个表达式匹配。对于如何调用过程本身并没有限制。
没有一个来源将回溯限制为仅贪婪或非贪婪量词。您可能会在former answer的中读到贪婪和非贪婪模式行为的差异Can I improve performance of this regular expression further 。简而言之,它们在机制(取回和重新匹配的方式)方面有所不同,但本质是相同的,如上面的定义所述。