正则学习杂感:磨刀不误砍柴功

September 23rd, 2009 Categories: 杂项

反复读紫龙书第三章,以及网文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一次才有礼貌。正则引擎在幕后默默无闻地做了那么多工作,不应该老是麻烦它老人家,呵呵。

Tags: , , ,

2 Responses to “正则学习杂感:磨刀不误砍柴功”

  1. October 8th, 2009 at 20:55
    1

    Hi,Rex
    我很早就看到你的网站了,最近手上在写的那本书,希望用到你的网站上的一些例子,不知你是否同意
    另外,你如果有gtalk的话,可否告诉我?给我发邮件到我留言时输入的邮箱就可以了
    谢谢

    [Reply]

    rex Reply:

    @Yurii 已经加上了:)

    [Reply]

Leave a Comment

如何在本站贴代码?

可以使用任意语言名称代替“python”.