-- Start
雖然支援Regex的工具有很多,但在這些工具的背後都是使用以下兩種引擎之一來解析字串。不同的引擎支援的元字元及工作原理是不同的,下面我們看看它們的工作原理。
非確定型有窮自動機(NFA):運算式主導
我們用運算式 reg(ress|ular) 匹配文本 I love regular expressions,NFA 引擎從運算式 r 開始,檢查當前運算式 r 是否和當前文本 I 匹配,如果不匹配,指標向後移一位,當前文本變為空白格,再次檢查當前運算式與當前文本是否匹配,如此反覆嘗試。如果指標移動到文本末尾時,仍然無法匹配,則報告匹配失敗。如果像本例這樣遇到多選分支該怎麼辦呢?引擎會在分支開始前儲存當前指標的位置,然後依次嘗試每一個分支,如果分支沒有匹配成功,則指標首先回退到最近的儲存位置(我們把這一過程稱為回溯),然後嘗試下一個分支,如果某一個分支匹配成功,則剩餘的分支將不再嘗試。所以有時候分支的順序特別重要。Never
ever 不要寫出類似下面的運算式。
\d*|\w 此運算式的第二個分支永遠也得不到嘗試的機會,因為第一個分支總是能夠匹配成功,考慮調換分支順序
love|love regular 如果第一個分支能夠匹配,那麼第二個分支將得不到嘗試的機會;如果第一個分支不能匹配,第二個分支也肯定不能匹配。考慮調換分支順序
如果用 exp|reg|lov 來匹配上面的文本 I love regular expressions,會得到什麼結果呢?如果你知道了答案,說明你看懂了上面的原理。
確定型有窮自動機(DFA):文本主導
我們用運算式 love|love regular 匹配文本 I love regular expressions,DFA 引擎會記錄當前所有可能的匹配,隨著指標向右移動,不能匹配的分支被淘汰出局,最後只剩下唯一的分支。本例中匹配的是love regular,顯然匹配的結果和分支的順序沒有任何關係,無論分支的順序如何,結果總是能夠匹配的分支中最長的那一個。由此可知,對於同樣的運算式love|love
regular,NFA 和DFA引擎會得到不同的結果,事實上,我們可以通過這個運算式來判斷引擎的類型。
對於目標文本的每一個字元,DFA 引擎最多隻檢查一遍,而 NFA 則有可能需要回溯。顯然 DFA 要更快一些,但是 DFA 也有致命傷,它不支援非貪婪量詞和捕獲型括弧。所以目前大部分工具都是使用 NFA 作為正則引擎。
由於 NFA 具有運算式主導的特性,通過改變運算式的編寫方式,我們可以對錶達式進行多方面的控制,一個好的運算式能給我們帶來很多收益,一個差的運算式將嚴重影響效能,甚至是記憶體溢出,而它們之間的差別就在一念之間。
測試引擎的類型
- 方法一:是否支援非貪婪量詞,捕獲型括弧和回溯,如果是,則是 NFA。
- 方法二:用運算式 love|love regular 匹配字串love regular,如果匹配了love,那就是 NFA。
- 方法三:用運算式 X(.+)+X 匹配字串=XX===============================,如果時間很長或記憶體溢出,則是 NFA。
--更多參見:Regex精萃
-- 聲 明:轉載請註明出處
-- Last Updated on 2012-05-26
-- Written by ShangBo on 2012-05-21
-- End