正則表達(dá)式的匹配原理

什么是正則表達(dá)式

工作中我們經(jīng)常使用正則表達(dá)式來解決問題。正則表達(dá)式又稱規(guī)則表達(dá)式,其實(shí)就是事先定義好的一些特定字符、及這些特定字符的組合,組成一個(gè)“規(guī)則字符串”,這個(gè)“規(guī)則字符串”用來表達(dá)對(duì)字符串的一種過濾邏輯。它是一個(gè)強(qiáng)大便捷高效的文本處理工具,正則表達(dá)式可以添加、刪除、分離、疊加、插入和修正各種類型的文本和數(shù)據(jù)。

正則表達(dá)式是一個(gè)工具,各種不同的語(yǔ)言對(duì)正則表達(dá)式可能都有著不同的實(shí)現(xiàn)。但是使用的方法大同小異,各個(gè)不同語(yǔ)言也有自己特有的特性和能力,需要我們?cè)趯?shí)際使用的過程中自己發(fā)掘。

正則表達(dá)式的原理

正則表達(dá)式應(yīng)用到目標(biāo)字符串大致分為下面幾步:
1、正則表達(dá)式編譯。
2、引擎?zhèn)鲃?dòng)開始
3、元素檢查
4、尋找匹配結(jié)果(成功則結(jié)束)
5、引擎?zhèn)鲃?dòng)裝置驅(qū)動(dòng)(下一個(gè)字符開始,回到3)
6、匹配徹底失敗(結(jié)束)

正則表達(dá)式運(yùn)行原理.png

我們知道正則表達(dá)式其實(shí)是一個(gè)“字符串”,因此編譯和引擎是什么呢?其實(shí)計(jì)算機(jī)在實(shí)際使用正則表達(dá)式的時(shí)候,并不是直接使用這個(gè)字符串,而是通過編譯翻譯成特定的機(jī)器,這個(gè)機(jī)器就是我們所說的引擎。

這個(gè)引擎分為兩種,NFA(非確定型有窮自動(dòng)機(jī))和DFA(確定型有窮自動(dòng)機(jī)),有印象嗎?學(xué)過編譯原理的同學(xué)們?沒學(xué)過或者忘了也不要緊。下面我們一起來學(xué)習(xí)下這兩種機(jī)器吧。

正則表達(dá)式引擎

我們通過一個(gè)例子來看看NFA和DFA有哪些不同吧。

對(duì)于正則表達(dá)式:(a|b)*abb來說,NFA和DFA的示意圖如下:

NFA.png
DFA.png

怎么樣,是不是有點(diǎn)懵懵的呢?

對(duì)于一個(gè)正則表達(dá)式來說通常情況下有三種形式ab(連接)a|b(或)a* (0到多個(gè)a)。對(duì)應(yīng)的三種形態(tài):

ab(連接).png
a|b(或).png
a*(0到多個(gè)a).png

基于這三種基本的形態(tài),根據(jù)正則表達(dá)式,我們很容易畫出NFA的模型。

NFA.gif

那么為什么我們要叫它不確定型呢?加入我們當(dāng)前的狀態(tài)是0,當(dāng)輸入a時(shí),我們既可以得到狀態(tài)0也可以得到狀態(tài)1,我們不確定得到的狀態(tài)是0還是1,所以這個(gè)自動(dòng)機(jī)是不確定型的。

那么DFA就是確定型有窮自動(dòng)機(jī),不管輸入什么我們都可以得到一個(gè)確定的狀態(tài),但是DFA又該如何得到呢?

DFA需要通過NFA推導(dǎo)出來。
1、首先我們開始的狀態(tài)是0
2、0狀態(tài)可以輸入a和b,我們先輸入a,這時(shí)可以得到0狀態(tài)或者1狀態(tài)。我們把這個(gè)狀態(tài)成為一個(gè)新的狀態(tài)(0,1),這個(gè)狀態(tài)是狀態(tài)0和狀態(tài)1的集合態(tài)。然后狀態(tài)0輸入b得到的還是狀態(tài)0。
3、然后看(0,1)狀態(tài)。根據(jù)NFA的圖,我們發(fā)現(xiàn)0可以輸入a和b,1可以輸入b,因此(0,1)可以輸入a和b。輸入a可以得到0和1,輸入b可以得到0和2。因此(0,1)輸入得到的還是(0,1),輸入b得到(0,2)。
4、根據(jù)上述規(guī)律繼續(xù)推導(dǎo),我們得到下面的圖。

生成DFA.gif

這時(shí)我們現(xiàn)在只有0,(0,1),(0,2),(0,3)這四種狀態(tài),改變下狀態(tài)的名稱就得到了最開始的DFA的狀態(tài)圖。

當(dāng)然這只是個(gè)簡(jiǎn)單的例子,實(shí)際中式子可能會(huì)非常復(fù)雜,DFA的狀態(tài)數(shù)可能會(huì)遠(yuǎn)遠(yuǎn)大于NFA的總狀態(tài)數(shù)。
那么NFA和DFA各自有什么特點(diǎn),對(duì)于正則表達(dá)式又有什么影響呢?

NFA與DFA

編譯速度:
通過上述的NFA和DFA的原理我們可以看到,NFA的狀態(tài)數(shù)與正則表達(dá)式的長(zhǎng)度有關(guān)系,而DFA的狀態(tài)數(shù)最大可能是NFA狀態(tài)數(shù)的排列組合之和。因此DFA編譯起來要比NFA復(fù)雜的多。

匹配速度:
在輸入一個(gè)字符之后,NFA可能到達(dá)的狀態(tài)不一樣,這時(shí)候需要進(jìn)行選擇,加入剛開始選擇的分支最終無法匹配,那么我們需要重新回退到這個(gè)選擇,選擇另一個(gè)分支進(jìn)行匹配。這就產(chǎn)生了回溯。而DFA到達(dá)的狀態(tài)是確定的,因此只需要匹配一遍字符串就可以得到結(jié)果。雖然DFA有編譯上的損耗,但是通常情況下回溯的損耗比較大,因此匹配上速度上DFA勝。

其他對(duì)比:
根據(jù)NFA和DFA的特點(diǎn),我們還可以知道一些其他的對(duì)比情況,感興趣的讀者可以去查相關(guān)的資料。

最終兩者的比較如下表:

NFA與DFA對(duì)比.png

現(xiàn)在大部分的語(yǔ)言都是基于NFA的,因?yàn)樗С值墓δ芨妗?/p>

匹配過程

NFA其實(shí)是表達(dá)式主導(dǎo)的,每次先檢查正則的一部分,當(dāng)遇到分歧時(shí),先檢查一個(gè)路徑如果適合則匹配,如果不適合,則回退到分歧點(diǎn)進(jìn)行另一部分的匹配,因此要檢查的文本字符可能被檢查多次,這就是回溯;
回溯(或者說選擇路徑)的原則有兩個(gè):1、優(yōu)先量詞還是忽略量詞,2、LIFO。后進(jìn)先出,回溯到最近的儲(chǔ)存的路徑。

DFA是文本主導(dǎo)的,掃描字符時(shí),會(huì)記錄”當(dāng)前有效“的所有匹配可能,盡可能多的匹配字符串。例如:DFA中,today去匹配to(day)?這樣的字符串,最終匹配出來的就是today。如果是toda去匹配則會(huì)得到to。DFA中每個(gè)字符只會(huì)匹配一次。

還是以(a|b)*abb這個(gè)為例,我們用分別用NFA和DFA來匹配babb這個(gè)字符串。
假設(shè)我們的NFA實(shí)現(xiàn)是以量詞優(yōu)先。
1、起始狀態(tài)0,輸入b得到狀態(tài)0
2、狀態(tài)0,輸入a可以得到0或者1,我們先記住這次選擇的路徑,由于是量詞優(yōu)先,我們選擇跳到狀態(tài)0
3、狀態(tài)0,輸入b得到0
4、狀態(tài)0,輸入b得到0,輸入完畢,0不是最終態(tài),回退到之前的分叉2
5、狀態(tài)0,輸入a,由于選過0,這次選擇到達(dá)狀態(tài)1。
6、狀態(tài)1,輸入b,得到狀態(tài)2
7、狀態(tài)2,輸入b,得到狀態(tài)3,輸入完畢,3是最終態(tài),匹配成功。

NFA匹配.gif

DFA匹配:
1、起始狀態(tài)0,輸入b得到狀態(tài)0
2、狀態(tài)0,輸入a得到狀態(tài)1
3、狀態(tài)1,輸入b得到狀態(tài)2
4、狀態(tài)2,輸入b得到狀態(tài)3,輸入完畢,狀態(tài)3是最終態(tài),匹配成功。

DFA匹配.gif

總結(jié)

正則表達(dá)式一直在用,但是一直也沒有研究過正則表達(dá)式是怎么實(shí)現(xiàn)的。因?yàn)橹翱吹竭^有人說正則表達(dá)式的匹配可能會(huì)卡進(jìn)程,剛開始不太相信,經(jīng)過這次的學(xué)習(xí)總結(jié),了解了正則表達(dá)式的原理,發(fā)現(xiàn)原來正則表達(dá)式的寫法真的會(huì)影響性能(由于大部分語(yǔ)言的實(shí)現(xiàn)都是基于NFA的)。這一篇先介紹原理,之后有時(shí)間會(huì)再出一篇,大家一塊研究探討下如何提高正則表達(dá)式的效率。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,527評(píng)論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,687評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,640評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,957評(píng)論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,682評(píng)論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,011評(píng)論 1 329
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,009評(píng)論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,183評(píng)論 0 290
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,714評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,435評(píng)論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,665評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,148評(píng)論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,838評(píng)論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,251評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,588評(píng)論 1 295
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,379評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,627評(píng)論 2 380

推薦閱讀更多精彩內(nèi)容