正则学习杂感:磨刀不误砍柴功
反复读紫龙书第三章,以及网文Write Your Own Regular Expression Parser(链接在这篇文章中找),连同该网文附带的源码,终于破关。一点感悟,写在这里。
使用正则表达式搜索字串,比逐位进行strcmp这样的方法要复杂N倍,如果说strcmp是只支持+-×÷的计算器的话,那么正则表达式就是一台现代化的电脑。正则式不用逐位比较,它有自己的一整套方法。
要想在源字串找某个正则式模式,需要先详尽地分析该正则式,其过程是将该正则式解剖成不可再分的字符(称为状态),然后从任意一个状态开始,通过不同的路径(字符输入)可以到达不同的状态。第一个字符之前,叫做初始状态;最后一个字符之后,叫做接收状态。这种是NFA(不确定的有穷自动机),因为一个状态上有可能存在不止一条的转出状态。
一旦做好了这样的状态集合,就可以进行匹配了。每输入一个字符,从开始状态上就会产生不同的状态集合;依次输入完毕,如果所得到状态集合中包含了一个接受状态,就证明所输入的串是匹配的。但是NFA的效率低下。因为从每个状态上转出的路径不止一条,因此就有回溯。为提升效率,可以将NFA转成等效的DFA,即确定的有穷自动机。
DFA的原理是,对于每个状态集合D和给定的输入字符a,最多只有一条通路可走。与NFA的区别是,对于每个单个的状态f和给定的字符a,就有N条路可走。但是DFA也不是生来就万能的,比方说,它有死状态需要消除,同构的状态需要合并,还存在对于复杂正则表达式的DFA的转换效率低、实现复杂度高的情况,等等。虽如此,NFA转换为DFA还是值得的,有道是磨刀不误砍柴功。
对于正则表达式做好了DFA,就可以进行匹配了。每输入一个字符,自动机就转至下一个状态集合,直至输入结尾。如果所达到的状态集合中包含了接受状态,那么匹配就是成功的。
以上就是NFA、DFA的原理。当然,细节是简化过的。否则的话,上面任何一个步骤都有N多的细节,需要使用各种奇怪的数据结构来存储,复杂的成员函数来操作。
说到这里,想起python, pcre,以及其它一些正则表达式库,都有compile一个选项。先编译再执行,一次编译多次执行,文档一再这样强调。这比一上来就execute效率要高,如果重复执行多次的话。以前总是图方便直接就execute了,现在想想,实现一个正则表达式多不容易呀,对于多次重复的匹配,还是老老实实地compile一次才有礼貌。正则引擎在幕后默默无闻地做了那么多工作,不应该老是麻烦它老人家,呵呵。
Hi,Rex
我很早就看到你的网站了,最近手上在写的那本书,希望用到你的网站上的一些例子,不知你是否同意
另外,你如果有gtalk的话,可否告诉我?给我发邮件到我留言时输入的邮箱就可以了
谢谢
[Reply]
rex Reply:
October 15th, 2009 at 12:39 pm
@Yurii 已经加上了:)
[Reply]