DFA与NFA引擎:他们的能力和限制有何不同?

时间:2010-10-20 13:38:27

标签: regex finite-automata dfa nfa

我正在寻找基于其功能和限制的DFA与NFA引擎之间差异的非技术性解释。

5 个答案:

答案 0 :(得分:65)

确定性有限自动机(DFA)和非确定性有限自动机(NFA)具有完全相同的能力和局限性。唯一的区别是符号方便。

有限自动机是具有状态和读取输入的处理器,每个输入字符可能将其设置为另一个状态。例如,状态可能是“只读取连续两个C”或“正在开始一个单词”。这些通常用于快速扫描文本以查找模式,例如对源代码进行词汇扫描以将其转换为标记。

确定性有限自动机一次处于一种状态,这是可实现的。非确定性有限自动机一次可以处于多个状态:例如,在标识符可以以数字开头的语言中,可能存在“读取数字”状态而另一个状态“读取标识符”,以及在阅读以“123”开头的内容时,NFA可能同时处于同一时间。实际应用哪种状态取决于它是否在单词结尾之前遇到了不是数字的东西。

现在,我们可以将“读取数字或标识符”表示为一个州本身,突然间我们不需要NFA。如果我们将NFA中的状态组合表示为状态本身,那么我们的DFA状态会比NFA多得多,但是它会做同样的事情。

这是一个更容易阅读或写作或处理的问题。 DFA本身更容易理解,但NFA通常更小。

答案 1 :(得分:12)

以下是微软的非技术性答案:

DFA引擎以线性时间运行,因为它们不需要回溯(因此它们从不测试相同的字符两次)。他们还可以保证匹配最长的字符串。但是,由于DFA引擎仅包含有限状态,因此它无法与具有反向引用的模式匹配,并且因为它不构造显式扩展,所以它无法捕获子表达式。

传统的NFA引擎运行所谓的“贪婪”匹配回溯算法,以特定顺序测试正则表达式的所有可能扩展并接受第一个匹配。由于传统的NFA为正式匹配构造了正则表达式的特定扩展,因此它可以捕获子表达式匹配和匹配反向引用。但是,由于传统的NFA回溯,如果状态通过不同的路径到达,它可以多次访问完全相同的状态。因此,在最坏的情况下,它可以以指数方式缓慢运行。因为传统的NFA接受它找到的第一个匹配,所以它也可以留下未被发现的其他(可能更长)的匹配。

POSIX NFA引擎就像传统的NFA引擎一样,只是它们会继续回溯,直到它们能够保证找到最长的匹配。因此,POSIX NFA引擎比传统的NFA引擎慢,而且当使用POSIX NFA时,您不能通过更改回溯搜索的顺序来支持较短的匹配。

传统的NFA引擎受到程序员的青睐,因为它们比DFA或POSIX NFA引擎更具表现力。虽然在最坏的情况下它们可以缓慢运行,但您可以使用减少模糊和限制回溯的模式来引导它们在线性或多项式时间内找到匹配。

[http://msdn.microsoft.com/en-us/library/0yzc2yb0.aspx]

答案 2 :(得分:6)

一个简单的,非技术性的解释,从杰弗里弗里德的书Mastering Regular Expressions转述。

<强> CAVEAT

虽然这本书通常被认为是“正则表达”,但是在DFA和NFA之间的区别是否真的是正确的,似乎存在一些争议。我不是计算机科学家,我不理解真正的“常规”表达背后的大部分理论,无论是否具有确定性。在争议开始之后,我因此删除了这个答案,但从那以后它在评论中引用了其他答案。我会非常有兴趣进一步讨论这个问题 - 弗里德尔真的错了吗?或者我得到弗里德错了(但我昨天晚上重读那一章,就像我记得的那样......)?

编辑:看来Friedl和我确实是错的。请查看以下Eamon的优秀评论。


原始回答:

DFA引擎逐个字符地逐步执行输入字符串,并尝试(并记住)此时正则表达式可以匹配的所有可能方式。如果它到达字符串的末尾,则声明成功。

想象一下字符串AAB和正则表达式A*AB。我们现在逐字逐句地逐字逐句。

  1. A

    • 第一个分支:可以A*匹配。
    • 第二个分支:可以通过忽略A*(允许零重复)并使用正则表达式中的第二个A进行匹配。
  2. A

    • 第一个分支:可以通过展开A*来匹配。
    • 第二个分支:B无法匹配。第二个分支失败。但是:
    • 第三个分支:可以通过不展开A*并使用第二个A进行匹配。
  3. B

    • 第一个分支:无法通过展开A*或将正则表达式移至下一个标记A来匹配。第一个分支失败。
    • 第三个分支:可以匹配。万岁!
  4. DFA引擎永远不会在字符串中回溯。


    NFA引擎通过令牌逐步执行 regex 令牌,并尝试对字符串进行所有可能的排列,必要时进行回溯。如果它到达正则表达式的末尾,则声明成功。

    想象一下与以前相同的字符串和相同的正则表达式。我们现在通过令牌遍历我们的正则表达式令牌:

    1. A*:匹配AA。记住回溯位置0(字符串的开头)和1。
    2. A:不匹配。但我们有一个回溯的位置,我们可以回来再试一次。正则表达式引擎退回一个字符。现在A匹配。
    3. B:匹配。达到了正则表达式的结束(有一个回溯位置)。万岁!

答案 3 :(得分:2)

正如他们的名字所说,NFA和DFA都是有限自动机。

两者都可以表示为起始状态,成功(或“接受”)状态(或成功状态集),以及列出转换的状态表。

在DFA的状态表中,每个<state₀, input>密钥都会转换为一个且只有一个state₁

在NFA的状态表中,每个<state₀, input>都会转换为设置状态。

当你拿DFA时,将它重置为它的开始状态,一系列输入符号,你知道它到底是什么结束状态以及它是否是成功状态。

然而,当您采用NFA时,对于每个输入符号,它将查找可能的结果状态集,并且(理论上)随机地,不确定地选择其中一个。如果存在一组随机选择导致该输入字符串的成功状态之一,则称该DFA对该字符串成功。换句话说,你应该假装它总是神奇地总是选择正确的。

计算中的一个早期问题是,由于这种魔力,NFA是否比DFA更强大,答案结果是没有,因为任何NFA都可以转换为等效的DFA。 他们的能力和限制完全相同。

答案 4 :(得分:0)

我发现Jan Goyvaerts的正则表达式,完整教程中给出的解释是最有用的。见本PDF第7页:

https://www.princeton.edu/~mlovett/reference/Regular-Expressions.pdf

在第7页中提出的其他要点中,有两种正则表达式引擎:文本引导引擎和正则表达式引擎。 Jeffrey Friedl分别将它们称为DFA和NFA引擎。 ......某些非常有用的功能,例如延迟量词和反向引用,只能在正则表达式引擎中实现。