2014年3月25日22:55從 http://code.google.com/p/febird/wiki/MultiRegexMatch 更新至最新版前端
This Multiple Regex Matching solution includes two parts:正則表達式
這個程序包含一個很是高效的算法,用來匹配多個正則表達式。通過預處理,僅用 O(n) 的時間複雜度,就能夠識別出一個輸入字符串(長度爲n)能匹配哪些(多是多個)正則表達式。算法的詳細內容可參見:算法
做爲一個完整的解決方案,這個程序包括兩部分:express
$ cd febird-trunk $ make -C tools/regex $ ll tools/regex/*/*.exe -rwxrwxrwx 1 leipeng leipeng 15M 2013-11-02 15:41:54 tools/regex/dbg/regex_build.exe -rwxrwxrwx 1 leipeng leipeng 26M 2013-11-02 15:42:06 tools/regex/rls/regex_build.exe
regex_builder.exe 將不少個正則表達式 offline build成一個DFA文件,online程序使用時,先加載DFA文件,當匹配文本時,能夠獲知匹配到了哪些正則表達式,同一個文本可能匹配多個正則表達式。api
匹配接口分文本接口於二進制接口兩種,目前二進制接口已經有了很友好的封裝,推薦使用。app
文本接口的使用方法與以前的DFA詞表徹底相同(match_key接口)。函數
該程序使用 re2 的parser前端,生成 febird 本身的 DFA 文件性能
命令行: regex_build.exe Options測試
Options 命令行選項 | 說明 |
-i Regex.txt | 輸入的正則表達式描述文件,也能夠經過標準輸入傳遞,該參數優先於標準輸入 |
-O regex_dfa_file | 生成的自動機文件 |
-a | 從全部位置開始匹配,至關於在全部正則表達式以前加 .* ,這會加快匹配速度,由於不須要從新從輸入文本的每一個位置開始搜索, 但會大大增長內存用量(20倍以上),build消耗的時間也會顯著增長 |
-A | 在全部正則表達式合併以後加 .* ,僅用於測試 |
-b binmeta_file | 生成 binmeta_file,是在 Binary 模式下獲取 Submatch 時使用的元信息 |
-g | 爲每一個正則表達式生成三個 dot 文件,該文件用來可視化正則表達式自動機的狀態圖NFA/DFA/MinimizedDFA |
-G | 生成整個DFA的dot文件,一般狀況下,該文件會很大 |
-L | 不使用UTF8,使用Latin1;不加該選項時(默認狀況)使用的是UTF8 |
-d delimiter | 將正則表達式看作Key,delimiter表示key,value之間的分隔符, build時會將該字符從正則表達式的DFA中刪除, 所以目標文本中出現此字符時,匹配就會失敗。默認是 256,在 byte 取值範圍以外 |
-c conflict_report_file | 當同一個文本會被多個正則表達式匹配時,此時稱爲衝突,該選項將衝突的正則表達式的id寫到conflict_report_file 不少時候衝突是不可避免的,可是,根據 confict_report_file,能夠修改正則表達式,儘量減少衝突的可能性 |
-s | 捕獲 submatch,也就是 () 中的部分,默認狀況下不捕獲 submatch |
-t dfa_type | 默認dfa_type=d, 表示 DenseDFA,專爲正則表達式優化的DFA d之外的其它字符,表示DFA類型爲通常DFA,主要爲詞表DFA優化 |
-D | 構建動態DFA以節省內存和構建時間,在某些狀況下,構建完整DFA甚至是不可能的, 若是沒指定該選項,該程序會嘗試用100倍於全部正則表達式的內存,若是失敗,仍然會構建動態DFA |
-I | 正則表達式忽略大小寫 |
一開始 febird DFA 經過 match_key 接口來實現正則表達式匹配,必須在 byte 的取值範圍 [0, 256) 之間取一個做爲分隔符。後來,通過仔細考慮,經過擴充自動機的字符集( r1303),從而 delimeter 能夠在 [0, 256) 以外取值,因而就再也不須要從 [0, 256) 取一個特殊值來做爲分隔符。
這樣,正則表達式匹配就能夠有更廣的適用範圍。另外一方面,表面上看,彷佛去除一個特殊byte值做爲delimeter會影響二進制模式的匹配,其實一點也不會。正則表達式至關於key,正則表達式的 id 至關因而 value,delimeter 不能出如今 key 中,但能夠出如今 value 中,從而,value能夠是任意二進制數據。實際上,二進制匹配接口的實現是先於 r1303 的。
因而,如今,只有在當 你知道你在幹什麼 的時候,才須要指定 -d delim 選項,不然,必定不要用 -d
regexp \t id優化
第一列是正則表達式,若是行首字符是 *,表示忽略該正則表達式的 one pass 屬性,無條件獲取 submatch,用 * 作標誌的緣由是以 * 開頭的正則表達式是非法的正則,從而不會引起歧義,也不會減小表達能力。
第二列是正則表達式的id,該id能夠是任意字符串,用來標識這條規則。多個正則表達式能夠有相同的id,此時等效於將多個正則表達式或起來放在一行。
a.*b a-dot-star-b a[a-f]*b 1 a[a-f]*([a-c]*)+[bc]+ 2 a(1|2|3|4)[ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab]{5} 3 a([0-3a-dx-z]{2,})[0-2cdxy]*abc 4 (1[358][0-9])[0-9]{8} mobile-phone-num \+86-(1[358][0-9])[0-9]{8} china-mobile-phone-num \d{3}\.\d{3}\.\d{3}\.\d{3} ip_address antidisestablishmentarianism 通常人能看懂的最長單詞
謹慎使用 .* ,特別是當 .* 處於正則表達式開頭時
普通字符串(不包括正則表達式的元字符)也能夠放進Regex.txt,能夠爲全部普通字符串賦予一個相同的id,這樣就將正則表達式和普通字符串build到同一個DFA中了,普通字符串在DFA中佔的空間相對要小得多,若是普通字符串不少,能夠嘗試用 -t x選項,看生成的DFA文件是否更小。
匹配接口使用方法能夠參考 DFA_Interface::match_key 示例程序
直接去 febird-trunk/samples/automata/abstract_api/ 目錄運行 make便可編譯,編譯輸出在 rls 和 dbg 目錄下
編譯出來的 match_key 程序可用來測驗匹配(match_key程序使用的 delimiter是 \t ):
febird-trunk/samples/automata/abstract_api/rls/match_key -t abcccb < samples.dfa 輸出:
abcccb ---------- ab value: idx=00000000 str=1 ab value: idx=00000001 str=2 ab value: idx=00000002 str=a-dot-star-b abc value: idx=00000000 str=2 abcc value: idx=00000000 str=2 abccc value: idx=00000000 str=2 abcccb value: idx=00000000 str=1 abcccb value: idx=00000001 str=2 abcccb value: idx=00000002 str=a-dot-star-b
輸出的 str=1 str=2 str= a-dot-star-b就是匹配到了id爲一、二、a-dot-star-b的正則表達式
使用 match_key 接口,正則表達式匹配和詞典匹配就徹底相同。