簡易正則表達式引擎的實現


  正則表達式基本每個程序員都會用到,實現正則表達式引擎卻似乎是一個很難的任務。實際上,掌握《編譯原理》前端的詞法分析部分知識就能夠實現一個簡單的正則表達式引擎。這里推薦一下網易雲課堂的課程。http://mooc.study.163.com/course/USTC-1000002001?tid=1000003000#/info

基本的正則表達式  正則表達式由字符與元字符組成,整個表達式用於描述符合某些特定特征的一類字符串,比如說表達式:abc,它表示 "abc" 這個字符串,由 'a', 'b', 'c' 三個字符按順序連接在一起。本文要實現的正則表達式比較簡單,只實現連接、選擇、閉包的功能。定義直接從ppt里截圖:

實現的大概步驟如下:

NFA指的是非確定自動機,對任意的字符,有多個狀態可以轉換。DFA指的是確定自動機,對任意的字符,最多只有一個狀態可以轉換。

Thompson算法是一個遞歸算法,先將單個字符轉換為nfa,再根據規則將nfa組合起來。單個字符(比如c)的轉化如下

 

兩個字符(比如e1e2)則中間用ε連接

接下來是選擇(比如e1|e2)

閉包(比如e1*)比較復雜

知道了如何將小的nfa組合成大的nfa,那怎么處理正則表達式,將其轉換為nfa呢?我們可以像處理四則運算那樣,用兩個棧來解決,但這只能應對簡單情況。還可以用遞歸下降分析構建抽象語法樹,a|b的語法樹如下,遞歸下降分析的具體做法可以看前面推薦的視頻或直接看源碼

由於nfa對任意的字符,有多個狀態可以轉換,我們需要將其轉換為dfa。我們的nfa實際上是ε-NFA,有很多ε邊,而dfa是沒有ε邊的,所以我們可以通過子集構造算法去除這些ε邊。子集構造算法的大概思路是將從狀態A出發接收某個字符能到達的所有狀態(包括接收字符后再通過ε邊到達)構成一個子集,這個子集所能到達的所有狀態又構成一個子集,到最后就能消除ε邊,得到dfa。

對於下圖的nfa

子集構造算法步驟如下

第一列第一行I的意思是從NFA的起始節點經過任意個ε所能到達的結點集合。Ia表示從該集合開始接收一個a所能到達的集合,Ib也就是接收一個b所能到達的狀態的集合。

如果Ia和Ib還沒出現在I,就把它們填在接下的I里。結果如下

得到dfa后再用Hopcroft算法最小化dfa,這個算法的思想是將等價的狀態濃縮為一個結點。比如對於以下dfa

可以簡化為

這樣我們就完成了整個步驟,對於輸入的字符串,如果能沿着dfa走到接收狀態,就說明能夠匹配。具體源碼看這里 可能有bug,最后的最小化dfa也沒有實現,輕噴。

最后推薦幾個相關鏈接

輪子哥的教程 http://www.cppblog.com/vczh/archive/2008/05/22/50763.html

http://www.cnblogs.com/cute/p/4021689.html 這個人寫得比較清楚

再推薦一下網易公開課的課程 http://mooc.study.163.com/learn/USTC-1000002001?tid=1000003000#/learn/content


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM