多正則表達式匹配工具 的用法

2014年3月25日22:55從 http://code.google.com/p/febird/wiki/MultiRegexMatch 更新至最新版前端

Introduction

This Multiple Regex Matching solution includes two parts:正則表達式

  • An offline multiple regex builder application: regex_builder
    1. regex_builder build multiple regex into a DFA file
    2. if using binary mode, generate an optional binmeta text file describe the regex meta info

  • An online multiple regex matching API
    1. Use the general API load the DFA built by regex_builder
    2. Construct the MultiRegexFullMatch object from the DFA
    3. Construct the MultiRegexSubMatch, if the submatch capture is required
      • Note: This algorithm could only capture submatch for one-pass regex
  • This algorithm is very efficient for large number(such as 1,000,000) of regex recognition, a shinning example is query classification
  • This algorithm could be regarded as a generic Key-Value map, which Key is a regular expression

介紹

這個程序包含一個很是高效的算法,用來匹配多個正則表達式。通過預處理,僅用 O(n) 的時間複雜度,就能夠識別出一個輸入字符串(長度爲n)能匹配哪些(多是多個)正則表達式。算法的詳細內容可參見:算法

  1. 多正則表達式匹配(Multiple Regular Expression Matching)
  2. 多正則表達式匹配 (Multiple Regular Expression Matching) 中的動態 DFA 算法

做爲一個完整的解決方案,這個程序包括兩部分:express

  • 一個離線 Build 程序:regex_build
    1. regex_build 會把輸入的正則表達式編譯成一個 DFA ,正則表達式的編譯使用了 re2 的前端 Parser
    2. 若是使用二進制模式,還會生成一個 binmeta 文本文件,用來描述 DFA 的元信息
      • 該文件生成後不可被更改,不然會產生未定義行爲
      • 目前應該首選二進制模式

  • 一個動態庫,提供匹配接口
    1. 從 (regex_build生成的) DFA 文件 和 binmeta(二進制模式) 文件 加載 並 建立出 用來執行匹配 的 對象
    2. 在二進制模式下,構造 MultiRegexFullMatch 對象執行全匹配,此時不獲取 !Submatch,僅返回能匹配上的正則表達式 ID:MultiRegexFullMatch示例程序
    3. 在二進制模式下,構造 MultiRegexSubmatch 對象執行匹配:MultiRegexSubmatch示例程序
      • MultiRegexSubmatch 僅能獲取 one-pass 正則的 submatch
      • one-pass 正則的判斷直接調用了 re2 的判斷函數 IsOnePass
        • 很不幸,該函數會將正則表達式 從([^到]+)到([^怎]+)怎麼走 判爲非 one-pass,但實際上,在 unicode 字符集內,它的確是 one-pass,只是 re2 的底層引擎是基於字節的,因此它認不出來
        • 若是你願意冒險,regex_build 給你一個選擇,將全部的正則表達式標爲 one-pass,MultiRegexSubmatch::match_utf8 在搜索完以後,會按 utf8 編碼規則作一個邊界修正,就能夠正確提取出 從([^到]+)到([^怎]+)怎麼走 中的 submatch 了
  • 該程序對大規模的規則系統(例如100萬個正則表達式)會很是有用,好比query分類

Compile

$ 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 使用方法

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 正則表達式忽略大小寫

關於 -d 選項

一開始 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

輸入文件Regex.txt 的格式

regexp \t id優化

第一列是正則表達式,若是行首字符是 *,表示忽略該正則表達式的 one pass 屬性,無條件獲取 submatch,用 * 作標誌的緣由是以 * 開頭的正則表達式是非法的正則,從而不會引起歧義,也不會減小表達能力。

第二列是正則表達式的id,該id能夠是任意字符串,用來標識這條規則。多個正則表達式能夠有相同的id,此時等效於將多個正則表達式或起來放在一行。

一個示例的Regex.txt

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文件是否更小。

匹配接口: 二進制模式

MultiRegexFullMatch

參考 MultiRegexFullMatch示例程序

MultiRegexSubMatch

參考 MultiRegexSubmatch示例程序

匹配接口: 文本模式

匹配接口使用方法能夠參考 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 接口,正則表達式匹配和詞典匹配就徹底相同。

相關文章
相關標籤/搜索