正则表达式引擎所使用的两种基本技术:非确定型有穷自动机(NFA)和确定型有穷自动机(DFA)。
NFA是基于表达式的(Regex-Directed),去匹对相配文档(文档作为有穷字母表Σ),而DFA是基于文本的(Text-Directed),去匹对相配正则表达式。
目前的主流正则引擎又分为3类:一、DFA,二、传统型NFA,三、POSIX NFA。
DFA:
DFA 引擎在线性时状态下执行,因为它们不要求回溯(并因此它们永远不测试相同的字符两次)。DFA 引擎还可以确保匹配最长的可能的字符串。但是,因为 DFA 引擎只包含有限的状态,所以它不能匹配具有反向引用的模式;并且因为它不构造显示扩展,所以它不可以捕获子表达式。
NFA:
传统的 NFA 引擎运行所谓的“贪婪的”匹配回溯算法,以指定顺序测试正则表达式的所有可能的扩展并接受第一个匹配项。因为传统的 NFA 构造正则表达式的特定扩展以获得成功的匹配,所以它可以捕获子表达式匹配和匹配的反向引用。?但是,因为传统的 NFA 回溯,所以它可以访问完全相同的状态多次(如果通过不同的路径到达该状态)。因此,在最坏情况下,它的执行速度可能非常慢。因为传统的 NFA 接受它找到的第一个匹配,所以它还可能会导致其他(可能更长)匹配未被发现。
NFA最重要的部分:回溯(backtracking)。回溯就像是在道路的每个分岔口留下一小堆面包屑。如果走了死路,就可以照原路返回,直到遇见面包屑标示的尚未尝试过的道路。如果那条路也走不通,你可以继续返回,找到下一堆面包屑,如此重复,直到找到出路,或者走完所有没有尝试过的路。
POSIX NFA:
POSIX NFA 引擎与传统的 NFA 引擎类似,不同的一点在于:在它们可以确保已找到了可能的最长的匹配之前,它们将继续回溯。因此,POSIX NFA 引擎的速度慢于传统的 NFA 引擎;并且在使用 POSIX NFA 时,您恐怕不会愿意在更改回溯搜索的顺序的情况下来支持较短的匹配搜索,而非较长的匹配搜索。
DFA与NFA对比:
1. DFA对于文本串里的每一个字符只需扫描一次,比较快,但特性较少;
NFA要翻来覆去吃字符、吐字符,速度慢,但是特性丰富,所以反而应用广泛。
当今主要的正则表达式引擎,如Perl、Ruby、Python的re模块、Java和.NET的regex库,都是NFA的。
2. 只有NFA支持lazy、backtracking、backreference,NFA缺省应用greedy模式,NFA可能会陷入递归险境导致性能极差。
DFA只包含有穷状态,匹对相配过程中无法捕获子表达式(分组)的匹对相配结果,因此也无法支持backreference。
DFA不能支持捕获括号和反向引用。
POSIX NFA会继续尝试backtracking,以试图像DFA相同找到最长左子正则式。因此POSIX NFA速度更慢。
3. NFA是最左子式匹配,而DFA是最长左子式匹配。
4. NFA的编译过程通常要快一些,需要的内存也更少一些。
对于“正常”情况下的简单文本匹配测试,两种引擎的速度差不多。
一般来说,DFA的速度与正则表达式无关,而NFA中两者直接相关。
5. 对正则表达式依赖性较量强的操作系统(大量应用正则做搜索匹对相配),最好完全把握NFA->DFA算法,充分理解所应用的正则表达式引擎的思想和特性。--- 使用AC多模匹配算法来进行转换?参见snort软件。
使用范围:
目前使用DFA引擎的程序主要有:awk,egrep,flex,lex,MySQL,Procmail等;
使用传统型NFA引擎的程序主要有:GNU Emacs,Java,ergp,less,more,.NET语言,PCRE library,Perl,PHP,Python,Ruby,sed,vi;
使用POSIX NFA引擎的程序主要有:mawk,Mortice Kern Systems’ utilities,GNU Emacs(使用时可以明确指定);
也有使用DFA/NFA混合的引擎:GNU awk,GNU grep/egrep,Tcl。GNU grep采取了一种简单但有效的策略。它尽可能多地使用DFA,在需要反向引用的时候,才切换到NFA。GNU awk的办法也差不多——在进行“是否匹配”的检查时,它采用GNU grep的DFA引擎,如果需要知道具体的匹配文本的内容,就采用不同的引擎。这里的“不同的引擎”就是NFA,利用自己的gensub函数,GNU awk能够很方便地提供捕获括号。
引擎库:
- PCRE(Perl Compatible Regular Expressions)是一个Perl库,包括 perl 兼容的正规表达式库。
- boost::regex
PCRE是一个轻量级的函数库,比Boost之中的正则表达式库小得多。PCRE十分易用,同时功能也很强大,性能超过了POSIX正则表达式库和一些经典的正则表达式库。
和Boost正则表达式库的比较显示,双方的性能相差无几,PCRE在匹配简单字符串时更快,Boost则在匹配较长字符串时胜出。PCRE被广泛使用在许多开源软件之中,最著名的莫过于Apache HTTP服务器和PHP脚本语言、R脚本语言,此外,正如从其名字所能看到的,PCRE也是perl语言的缺省正则库。
- 微信扫码赞助
- 支付宝赞助