前一段時間,在將 多正則表達式匹配工具 用於數十萬任意的正則表達式時,之前一直擔憂的問題終於出現了:NFA 轉化 DFA 時的指數爆炸,那樣的 DFA 根本建立不出來,由於那些正則表達式之間有不可預料的各類交集!正則表達式
這個問題對我打擊很大,我甚至頓時以爲 多正則表達式匹配工具 徹底是個廢柴,最多,是個玩具!可是,只有挑戰,才能激勵人的鬥志,挖掘人的潛能。我想起了曾經對之不屑一顧的動態 DFA 匹配算法,以前我在研究 RE2 時知道,RE2 在動態 DFA 的內存用量達到限定時,會拋棄已經建立整個動態 DFA,由於 DFA 的狀態圖比較複雜,節點之間互相引用,沒法象普通的 Cache 同樣部分的進行 Swap ,直覺上對它就沒有好印象。算法
可是碰到組合爆炸這個魔咒,只有嘗試一下,就先用 RE2 中的 set 試一下,先從那數十萬正則表達式中任選一萬個,re2 執行卻是很快,但立馬就提示 DFA Out Of Memory 了,而後我嘗試將 re2 的內存設到 8G,仍是不行,浪費若干腦細胞,最後才驚奇地發現,Re2 的內存限制用的是 int 來表示的,而 int 的事實標準是32 bit,最大隻能是 2G-1!設成 2G-1以後,re2 運行正常,性能還不錯。工具
因而我開始加碼,將全部正則表達式都扔進去,果真,re2 崩了!性能
雖然如此,可是至少代表,動態 DFA 解決該問題是可行的,我開始實現個人計劃。一切都很順利:測試
以前我實現其餘算法時(r1303),擴展了自動機的字符集,而沒有在自動機的狀態上打專用 Tag,這個決定真是明智之舉,在這裏又用上了:google
ch=256 | 表示括號捕獲 | 用於我最先實現 One Pass 正則表達式的 DFA 算法 |
ch=257 | 表示全匹配 | 以前在一遍掃描中捕獲全部括號時,發現因括號位置太靠前而致使嚴重的性能問題, 就實現了兩遍掃描捕獲括號,第一遍只看全匹配,得到正則表達式ID, 第二遍專門針對具體正則ID捕獲括號,性能要好的多 |
ch=258 | 表示僞Epsilon轉移 | 這是實現動態 DFA 匹配的一個根基,不過這個僞 Epsilon 轉移只起到一個鏈表的做用,將全部子 DFA 的根(初始狀態)鏈起來 |
若是一切都照抄 re2 的實現,那不過是無聊的體力勞動。個人動態 DFA 實現,徹底創建在我以前的各類自動機算法之上,有了這個根基,個人實現相比 re2,有不少優點:spa