为了回答你的问题,你应该简要研究一下
乔姆斯基层次结构。这是一种古老而美丽的方式,将形式语言组织成逐渐增加复杂性的集合。层次结构的最低层是正则语言。你可能会猜到 - 你会发现 - RL恰好可以用“纯”正则表达式表示:只有字母表、空字符串、连接、交替|和Kleene星号*(看,没有反向引用)。形式语言理论的一个经典定理 - Kleene定理 - 是DFA、NFA(如你所引用的文章中所描述的)和正则表达式都具有完全相同的能力来表示和识别语言。文章中给出的Thompson构造是定理证明的一部分。
每个RL也是CFL。但是有无限多个CFL不是正则的。使它们过于复杂而无法成为正则的CFL的一个特征是平衡的一对东西:括号、开始-结束块等等。几乎所有编程语言都是CFL。CFL可以通过称为
下推自动机的东西有效地识别。这本质上是一个带有
堆栈的NFA。堆栈会增长到需要的大小,因此它不再是有限自动机。真正的编程语言解析器几乎都是下推自动机的变体。
考虑具有反向引用的正则表达式。
^(b*a)\1$
简而言之,这代表长度为2n的字符串(其中n是任意正整数),第n个和第2n个字符都是a
,其余字符都是b
。这是一个典型的不规则CFL例子。可以使用另一个称为泵引理的形式语言工具来严格证明这一点。
这也是为什么反向引用会导致问题的原因!它们允许表示不规则语言的“正则表达式”。因此,无论如何都没有NFA或DFA能够识别它们。
但是,请注意,情况比我迄今为止所描述的更糟糕。考虑以下内容:
^(b*a)\1\1$
我们现在有一个长度为3n的字符串,其中第n个、第2n个和第3n个元素是
a
,而其他所有元素都是
b
。还有另一种泵引理的变体,它允许证明这种语言甚至太复杂,无法成为上下文无关语言!没有下推自动机可以识别它。
反向引用使得这些超级正则表达式能够表示三级上的Chomsky层次结构:上下文有关语言。粗略地说,识别CSL的唯一方法是检查相等长度的语言中的所有字符串(至少如果P!=NP,但这对于所有实际目的来说都是真实的,是一个完全不同的故事)。这样的字符串数量是指数级的,与您匹配的字符串长度成正比。
这就是为什么需要搜索正则表达式匹配器的原因。你可以设计非常聪明的搜索方式。但总会有一些输入会导致它花费指数时间。
所以我同意您引用的论文的作者。可以编写看起来非常无辜的正则表达式,没有反向引用,几乎可以有效地识别所有输入,但存在某些输入,导致Perl或Java或Python正则表达式匹配器 - 因为它是回溯搜索 - 需要数百万年才能完成匹配。这很疯狂。您可以编写一个脚本,它在多年内都是正确的,并且运行良好,然后有一天会因为偶然遇到了其中一个坏输入而锁定。假设正则表达式嵌入在你所乘坐的飞机的导航系统的消息解析器中...
根据请求,我将概述如何使用泵引理证明语言
a^k b a^k b
不是正则的。这里
a^k
是
a
重复
k
次的缩写。PL表示必须存在一个正整数N,使得长度至少为N的正则语言中的每个字符串必须采用R S T的形式,以便R S^k T也适用于所有自然数k。这里
R
,
S
,
T
是字符串,
S
可能不为空。
PL的证明依赖于一个事实,即每种正则语言都对应着某个DFA。对于其状态数(等同于引理中的L)更长的接受输入必须导致它“循环”:重复一个状态。称此状态为X。该机器使用一些字符串R从开始到达X,然后使用S回到X,然后使用T到达接受状态。嗯,在输入中添加额外的S副本(或删除S)仅对应于从X返回X的不同数量的“循环”。因此,具有附加(或删除)S副本的新字符串也将被接受。
由于每个 RL 都必须满足 PL,证明一个语言不是正则的方法是通过展示它与 PL 相矛盾。对于我们的语言来说,这并不难。假设您试图说服我语言 L = "a^k b a^k b" 满足 PL。因为它确实如此,所以您必须能够给出一些值 N(见上文):识别 L 的理论 DFA 中状态的数量。此时,我会说,“好吧,普通先生,考虑字符串 B = 'a^N b a^N b'”。如果 L 是正则的,则 B 必须导致该 DFA 在前 N 个字符内循环,这些字符必须全部是 'a'!因此,循环(上面的字符串 S)也包含所有的 'a'。有了这个,我就可以立即证明您关于 L 是正则的说法是错误的。我选择再绕一圈。这将导致您的理论 DFA 接受一个新字符串 'a^M b a^N b',其中 M > N,因为我在其前半部分添加了 'a'。哎呀!这个新字符串不在 L 中,因此 PL 并不成立。由于我每次都可以使用这个技巧,无论您提供了什么 N,PL 都不能适用于 L,因此 L 最终不能是正则的。
由于它不是正则的,Kleene 定理告诉我们没有 DFA、FA 或“纯”正则表达式可以描述它。
证明反向引用允许甚至不是上下文无关的语言具有非常相似的结构,但需要关于下推自动机的背景知识,我在这里不会给出。Google 可以提供。
注:这两个证明都不足以证明反向引用使识别成为 NP 完全问题。它们只是以非常严谨的方式表明反向引用将实际复杂性添加到纯正则表达式中。它们允许使用任何具有有限内存的机器或仅具有无限大 LIFO 内存的机器无法识别的语言。我将把 NP 完全性证明留给其他人。