【regex】如何判断正则引擎是 DFA 还是 NFA
一般的正则引擎会分为 NFA
, DFA
和 POSIX NFA
,为了区分,前者被称作传统 NFA
,NFA
和DFA
经常被类比为烧汽油的汽车和烧电的,烧电的一般看着会高档很多,烧汽油的乍一看会笨重很多,但是笨重,就有丰富的元字符的支持,两者在实现上也各有千秋,下面先看一下如何判断正则引擎是 DFA 还是 NFA。
如何判断
首先需要明确的是,DFA
并不支持忽略优先量词
,因此,判断你当前的正则引擎支不支持忽略优先量词
,基本就能确定了。还有一种方法,可以使用多选结构来判断。
写一个简单的字符串
nfa not
用正则(nfa | nfa not)
去匹配。
如果正则引擎是 NFA
,那么将会匹配到 “nfa”,如果是DFA
,那么将会匹配到 “nfa not”,这和NFA
和DFA
的匹配机制有关。
如果正则引擎是 NFA
,NFA
开始匹配的时候,由于是多选结构,NFA
通常会从左往右依次尝试,如果匹配失败,则回溯到多选结构前,然后开始尝试第二个,当匹配这个串时,nfa 匹配成功!就不会接着往后匹配了,返回结果。
如果正则引擎是DFA
,DFA
会始终选择长度最长的多选结构的选项,这是啥意思?DFA
在编译正则的时候,会首先做一系列的优化措施,以便后面的匹配更加轻松,于是,说出来你们可能不信,DFA
会记得所有的匹配可能,那么它的匹配过程大概是这样的。
刚开始匹配到 “nfa”,匹配成功,但是它发现往后也能继续匹配成功,于是最终匹配到 “nfa not”。
这也是为啥DFA
要比NFA
快很多的原因了。一般来说,回溯是NFA
的灵魂,DFA
中没有回溯,因为它从一开始就知道正则的所有结果,所以正则的好坏是不会影响DFA
的,但是会影响NFA
,NFA
总会给人一种“不到黄河不死心”的感觉。一般的,NFA
去匹配的话,如果匹配失败,NFA
会尝试回溯,因为它并不知道后面还有没有可能匹配成功,他是蒙在鼓里的,但是DFA
从一开始就知道,所有的匹配可能。