有限状态自动机java实现_用java开发编译器之:Thompson构造,将正则表达式转换为有限状态自动机...
閱讀博客的朋友可以到我的網(wǎng)易云課堂中,通過(guò)視頻的方式查看代碼的調(diào)試和執(zhí)行過(guò)程:
上一節(jié),我們通過(guò)代碼,實(shí)現(xiàn)了一個(gè)有限狀態(tài)自動(dòng)機(jī),并將其應(yīng)用于對(duì)整形和浮點(diǎn)數(shù)的識(shí)別。構(gòu)造有限狀態(tài)自動(dòng)機(jī),并驅(qū)動(dòng)它,從而實(shí)現(xiàn)對(duì)輸入字符串的識(shí)別,整個(gè)過(guò)程就是詞法分析的本質(zhì)。
上一節(jié)所開(kāi)發(fā)的狀態(tài)機(jī),基于以下模型:
這個(gè)模型,是我們?cè)诖a中,手動(dòng)寫(xiě)入程序的。實(shí)則上,它對(duì)應(yīng)著一組正則表達(dá)式:
D???????[0-9] ?表示0-9的字符類
{D}+????表示由 0-9 構(gòu)成的整形數(shù)值
({D}+ | {D}*\. {D}+ | {D}+ \. {D}*)(e{D}+)?表示浮點(diǎn)數(shù)或科學(xué)計(jì)數(shù)法
其中{D}+ 對(duì)應(yīng)著狀態(tài)機(jī)中,由0到1,然后在1中自轉(zhuǎn)這一流程。最后一個(gè)正則表達(dá)式,對(duì)應(yīng)圖中由狀態(tài)0到狀態(tài)2,或4的流程。
那么,問(wèn)題來(lái)了,給定一個(gè)正則表達(dá)式,可否直接生成一個(gè)有限狀態(tài)自動(dòng)機(jī)呢?答案是肯定的,大多數(shù)正則表達(dá)式識(shí)別程序,基本上都是先將其轉(zhuǎn)換為自動(dòng)機(jī),然后通過(guò)驅(qū)動(dòng)自動(dòng)機(jī)來(lái)識(shí)別輸入的,將正則表達(dá)式轉(zhuǎn)換為有限狀態(tài)自動(dòng)機(jī)將是我們這幾節(jié)的重點(diǎn)。
有限狀態(tài)自動(dòng)機(jī)的分類
有限狀態(tài)自動(dòng)機(jī),其實(shí)可以分成兩類。第一類是我們上面給出的,叫做確定性有限狀態(tài)自動(dòng)機(jī): Deterministic finite automaton 簡(jiǎn)稱DFA. 確定性的狀態(tài)機(jī)有一個(gè)特點(diǎn),就是給定當(dāng)前狀態(tài)和輸入字符,那么下一個(gè)狀態(tài)就能被唯一確定。例如基于上圖,在狀態(tài)1時(shí),接收到字符0-9,那下一個(gè)狀態(tài)一定只能是1,如果接收到字符 . ,那下一個(gè)狀態(tài),就一定只能是2. 更嚴(yán)謹(jǐn)?shù)恼f(shuō), DFA 是這樣一種自動(dòng)機(jī),從給定狀態(tài)出去的邊都對(duì)應(yīng)著一個(gè)確定的字符,同時(shí),從一個(gè)狀態(tài)出去的兩條邊,他們對(duì)應(yīng)的字符必定是不同的。
對(duì)應(yīng)于DFA, 另一種狀態(tài)機(jī)叫非確定性有限狀態(tài)機(jī): Nondeterministic finite automaton, 即NFA. 在實(shí)踐中,要想順利的將正則表達(dá)式轉(zhuǎn)換為自動(dòng)機(jī),需要NFA的幫助。NFA 的特點(diǎn)是,從一個(gè)狀態(tài)出去的兩條邊,可以有相同的對(duì)應(yīng)字符。或者它的邊可以對(duì)應(yīng)一種特殊的字符叫”空”字符,該字符對(duì)應(yīng)的符號(hào)是: ?.這種邊表示,不需要任何輸入,就可以從當(dāng)前狀態(tài)進(jìn)入下一個(gè)狀態(tài)。
舉個(gè)例子,表達(dá)式(and | any) , 它對(duì)應(yīng)的DFA如下:
它對(duì)應(yīng)的NFA 如下:
從初始狀態(tài)開(kāi)始,分化出兩條邊,兩條邊對(duì)應(yīng)的字符是一樣的
或者:
從初始狀態(tài)分化兩條對(duì)應(yīng)字符為空字符的邊,然后分別進(jìn)入兩個(gè)對(duì)應(yīng)的狀態(tài)機(jī)
第二種NFA在程序設(shè)計(jì)中容易實(shí)現(xiàn),因此,在下一節(jié)的代碼中,我們將采用第二種NFA的實(shí)現(xiàn)模式。
NFA有一個(gè)明顯的弱點(diǎn)就是,在代碼設(shè)計(jì)中,很難用數(shù)據(jù)結(jié)構(gòu)來(lái)對(duì)它進(jìn)行表示。特別是,當(dāng)對(duì)應(yīng)于一個(gè)輸入字符,NFA可以跳轉(zhuǎn)到多個(gè)狀態(tài),那么,要想利用NFA去識(shí)別輸入字符串就比較困難。一般而言,使用NFA的程序都需要經(jīng)過(guò)下兩個(gè)步驟:將正則表達(dá)式轉(zhuǎn)換為NFA, 將NFA轉(zhuǎn)換為DFA. 在后面的討論中,我們將通過(guò)代碼來(lái)展示這兩種轉(zhuǎn)換.
Thompson 構(gòu)造法
將正則表達(dá)式轉(zhuǎn)換為NFA的算法是由貝爾實(shí)驗(yàn)室的Ken Thompson 給出的,這哥們跟丹尼斯.里奇共同開(kāi)發(fā)了Unix, 而他開(kāi)發(fā)了C語(yǔ)言的前身 B 語(yǔ)言。
他的算法如下:
最簡(jiǎn)單的正則表達(dá)式是單字符匹配,例如a 匹配輸入字符”a”, 那么該表達(dá)式的NFA 構(gòu)造如下:
那么,兩個(gè)這樣的正則表達(dá)式合成的連接表達(dá)式ab 可以表示如下:
實(shí)際上,它是先分別構(gòu)造出兩個(gè)表達(dá)式的NFA, 然后通過(guò)一條?邊,將兩個(gè)NFA首尾連接起來(lái)。
下面我們看看,兩個(gè)表達(dá)式進(jìn)行 OR 操作的時(shí)候 | ,NFA怎么構(gòu)造,構(gòu)造圖如下:
要構(gòu)造兩個(gè)表達(dá)式的或操作: exp1 | exp2, 根據(jù)圖示,首先分別構(gòu)造兩個(gè)表達(dá)式exp1 , exp2 各自的NFA: NFA1(上頭虛線框), NFA2(下頭虛線框), 然后再構(gòu)造兩個(gè)狀態(tài),初始狀態(tài)(開(kāi)頭圓圈節(jié)點(diǎn)),和結(jié)束狀態(tài)(末尾圓圈節(jié)點(diǎn)),初始狀態(tài)延生處兩條 ? 邊,分別指向NFA1 和 NFA2 的開(kāi)頭,然后NFA1 和 NFA2的結(jié)尾各自延生出一條?邊,分別共同指向結(jié)束狀態(tài)。
我們?cè)倏纯?a | b 的NFA圖:
其原理跟前面所描述的是一樣的。上頭虛線框是表達(dá)式 a 的NFA, 下頭虛線框是表達(dá)式 b 的NFA. 兩個(gè)NFA的連接跟前面描述的一模一樣
如果表達(dá)式是( (a|b) | cd) 呢,算法也同理,先構(gòu)造 a | b 的NFA圖,然后構(gòu)造cd的NFA圖。最后根據(jù)前面所說(shuō)的辦法,再將兩個(gè)NFA連接起來(lái):
上頭大虛線框是 (a|d) 的NFA, 下頭長(zhǎng)匾虛線框是 cd的NFA. 然后首尾通過(guò)兩個(gè)狀態(tài)節(jié)點(diǎn)和ε邊連接起來(lái)。
大家可以看到, Thompson構(gòu)造算法其實(shí)是一個(gè)自我遞歸的過(guò)程
我們?cè)倏纯聪鄳?yīng)的閉包操作的構(gòu)造過(guò)程:
exp*的NFA:
如果是自我從復(fù)0次,那直接從下面的邊走到末尾節(jié)點(diǎn)。
exp+(至少重復(fù)一次) 的NFA:
exp?(重復(fù)0或1次)的NFA:
任何復(fù)雜的正則表達(dá)式它的NFA的構(gòu)造都是上面幾種構(gòu)造的組合, 例如表達(dá)式
(D*\.D| D\.D*)
構(gòu)造算法如下:
1.??構(gòu)造 D 的NFA:
2.??構(gòu)造 D*:
3.??構(gòu)造 D*\.D (由于.在正則表達(dá)式中是特殊字符,如果要僅僅想要表達(dá)它的符號(hào)內(nèi)容,要在前面加上反斜杠做轉(zhuǎn)義):
. 號(hào)的前部分是D*, 后部分是 D 的NFA.
4.??構(gòu)造 D\.D*, 該表達(dá)式的NFA其實(shí)就是將上圖 . 后面的部分挪到開(kāi)頭。
5.??根據(jù)OR 的構(gòu)造法, 構(gòu)造整個(gè)表達(dá)式 (D*\.D | D\.D*)的NFA:
上頭是 D*\.D 的NFA, 下頭是 D\.D*的NFA
再?gòu)?fù)雜的表達(dá)式的NFA的構(gòu)造,都是幾種基礎(chǔ)構(gòu)造的重復(fù)組合運(yùn)用。
我們這一節(jié)對(duì)概念和算法的介紹就到這里,根據(jù)我的習(xí)性,下一節(jié)肯定就是上代碼了。
原文:http://blog.csdn.net/tyler_download/article/details/51072362
總結(jié)
以上是生活随笔為你收集整理的有限状态自动机java实现_用java开发编译器之:Thompson构造,将正则表达式转换为有限状态自动机...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 系统测试相关知识笔记
- 下一篇: IMX6Q获取序列号方法