正則表達式的功法大全,做NLP再也不怕搞不定字符串了
在自然語言處理中,很多時候我們都需要從文本或字符串中抽取出想要的信息,并進一步做語義理解或其它處理。在本文中,作者由基礎到高級介紹了很多正則表達式,這些表達式或規則在很多編程語言中都是通用的。
正則表達式(regex 或 regexp)對于從文本中抽取信息極其有用,它一般會搜索匹配特定模式的語句,而這種模式及具體的 ASCII 序列或 Unicode 字符。從解析/替代字符串、預處理數據到網頁爬取,正則表達式的應用范圍非常廣。
其中一個比較有意思的地方是,只要我們學會了正則表達式的語句,我們幾乎可以將其應用于多有的編程語言,包括 JavaScript、Python、Ruby 和 Java 等。只不過對于各編程語言所支持的***級特征與語法有細微的區別。
下面我們可以具體討論一些案例與解釋。
一、基本語句
1. 錨點:^ 和 $
- ^The 匹配任何以“The”開頭的字符串 -> Try it! (https://regex101.com/r/cO8lqs/2)
- end$ 匹配以“end”為結尾的字符串
- ^The end$ 抽取匹配從“The”開始到“end”結束的字符串
- roar 匹配任何帶有文本“roar”的字符串
2. 數量符:*、+、?和 {}
- abc* 匹配在“ab”后面跟著零個或多個“c”的字符串 -> Try it! (https://regex101.com/r/cO8lqs/1)
- abc+ 匹配在“ab”后面跟著一個或多個“c”的字符串
- abc? 匹配在“ab”后面跟著零個或一個“c”的字符串
- abc{2} 匹配在“ab”后面跟著兩個“c”的字符串
- abc{2,} 匹配在“ab”后面跟著兩個或更多“c”的字符串
- abc{2,5} 匹配在“ab”后面跟著2到5個“c”的字符串
- a(bc)* 匹配在“a”后面跟著零個或更多“bc”序列的字符串
- a(bc){2,5} 匹配在“a”后面跟著2到5個“bc”序列的字符串
3. 或運算符:| 、 []
- a(b|c) 匹配在“a”后面跟著“b”或“c”的字符串 -> Try it! (https://regex101.com/r/cO8lqs/3)
- a[bc] 匹配在“a”后面跟著“b”或“c”的字符串
4. 字符類:\d、\d、\s 和 .
- \d 匹配數字型的單個字符 -> Try it! (https://regex101.com/r/cO8lqs/4)
- \w 匹配單個詞字(字母加下劃線) -> Try it! (https://regex101.com/r/cO8lqs/4)
- \s 匹配單個空格字符(包括制表符和換行符)
- . 匹配任意字符 -> Try it! (https://regex101.com/r/cO8lqs/5)
使用「.」運算符需要非常小心,因為常見類或排除型字符類都要更快與精確。\d、\w 和\s 同樣有它們各自的排除型字符類,即\D、\W 和\S。例如\D 將執行與\d 完全相反的匹配方法:
- \D 匹配單個非數字型的字符 -> Try it! (https://regex101.com/r/cO8lqs/6)
為了正確地匹配,我們必須使用轉義符反斜杠「\」定義我們需要匹配的符號「^.[$()|*+?{\」,因為我們可能認為這些符號在原文本中有特殊的含義。
- \$\d 匹配在單個數字前有符號“$”的字符串 -> Try it! (https://regex101.com/r/cO8lqs/9)
注意我們同樣能匹配 non-printable 字符,例如 Tab 符「\t」、換行符「\n」和回車符「\r」
5. Flags
我們已經了解如何構建正則表達式,但仍然遺漏了一個非常基礎的概念:flags。
正則表達式通常以/abc/這種形式出現,其中搜索模式由兩個反斜杠「/」分離。而在模式的結尾,我們通常可以指定以下 flag 配置或它們的組合:
- g(global)在***次完成匹配后并不會返回結果,它會繼續搜索剩下的文本。
- m(multi line)允許使用^和$匹配一行的開始和結尾,而不是整個序列。
- i(insensitive)令整個表達式不區分大小寫(例如/aBc/i 將匹配 AbC)。
二、中級語句
1. 分組和捕獲:()
- a(bc) 圓括弧會創建一個捕獲性分組,它會捕獲匹配項“bc” -> Try it! (https://regex101.com/r/cO8lqs/11)
- a(?:bc)* 使用 “?:” 會使捕獲分組失效,只需要匹配前面的“a” -> Try it! (https://regex101.com/r/cO8lqs/12)
- a(?<foo>bc) 使用 “?<foo>” 會為分組配置一個名稱 -> Try it! (https://regex101.com/r/cO8lqs/17)
捕獲性圓括號 () 和非捕獲性圓括弧 (?:) 對于從字符串或數據中抽取信息非常重要,我們可以使用 Python 等不同的編程語言實現這一功能。從多個分組中捕獲的多個匹配項將以經典的數組形式展示:我們可以使用匹配結果的索引訪問它們的值。
如果需要為分組添加名稱(使用 (?
2. 方括弧表達式:[]
- [abc] 匹配帶有一個“a”、“ab”或“ac”的字符串 -> 與 a|b|c 一樣 -> Try it! (https://regex101.com/r/cO8lqs/7)
- [a-c] 匹配帶有一個“a”、“ab”或“ac”的字符串 -> 與 a|b|c 一樣
- [a-fA-F0-9] 匹配一個代表16進制數字的字符串,不區分大小寫 -> Try it! (https://regex101.com/r/cO8lqs/22)
- [0-9]% 匹配在%符號前面帶有0到9這幾個字符的字符串
- [^a-zA-Z] 匹配不帶a到z或A到Z的字符串,其中^為否定表達式 -> Try it! (https://regex101.com/r/cO8lqs/10)
記住在方括弧內,所有特殊字符(包括反斜杠\)都會失去它們應有的意義。
3. Greedy 和 Lazy 匹配
數量符(* + {})是一種貪心運算符,所以它們會遍歷給定的文本,并盡可能匹配。例如,<.+> 可以匹配文本「This is a <div> simple div </div> test」中的「<div>simple div</div>」。為了僅捕獲 div 標簽,我們需要使用「?」令貪心搜索變得 Lazy 一點:
- <.+?> 一次或多次匹配 “<” 和 “>” 里面的任何字符,可按需擴展 -> Try it! (https://regex101.com/r/cO8lqs/24)
注意更好的解決方案應該需要避免使用「.」,這有利于實現更嚴格的正則表達式:
- <[^<>]+> 一次或多次匹配 “<” 和 “>” 里面的任何字符,除去 “<” 或 “>” 字符 -> Try it! (https://regex101.com/r/cO8lqs/23)
三、高級語句
1. 邊界符:\b 和 \B
- \babc\b 執行整詞匹配搜索 -> Try it! (https://regex101.com/r/cO8lqs/25)
\b 如插入符號那樣表示一個錨點(它與$和^相同)來匹配位置,其中一邊是一個單詞符號(如\w),另一邊不是單詞符號(例如它可能是字符串的起始點或空格符號)。
它同樣能表達相反的非單詞邊界「\B」,它會匹配「\b」不會匹配的位置,如果我們希望找到被單詞字符環繞的搜索模式,就可以使用它。
- \Babc\B 只要是被單詞字符環繞的模式就會匹配 -> Try it! (https://regex101.com/r/cO8lqs/26)
2. 前向匹配和后向匹配:(?=) 和 (?<=)
- d(?=r) 只有在后面跟著“r”的時候才匹配“d”,但是“r”并不會成為整個正則表達式匹配的一部分 -> Try it! (https://regex101.com/r/cO8lqs/18)
- (?<=r)d 只有在前面跟著“r”時才匹配“d”,但是“r”并不會成為整個正則表達式匹配的一部分 -> Try it! (https://regex101.com/r/cO8lqs/19)
我們同樣能使用否定運算子:
- d(?!r) 只有在后面不跟著“r”的時候才匹配“d”,但是“r”并不會成為整個正則表達式匹配的一部分 -> Try it! (https://regex101.com/r/cO8lqs/20)
- (?<!r)d 只有在前面不跟著“r”時才匹配“d”,但是“r”并不會成為整個正則表達式匹配的一部分* *->* **Try it!* (https://regex101.com/r/cO8lqs/21)
四、結語
正如上文所示,正則表達式的應用領域非常廣,很可能各位讀者在開發的過程中已經遇到了它,下面是正則表達式常用的領域:
- 數據驗證,例如檢查時間字符串是否符合格式;
- 數據抓取,以特定順序抓取包含特定文本或內容的網頁;
- 數據包裝,將數據從某種原格式轉換為另外一種格式;
- 字符串解析,例如捕獲所擁有 URL 的 GET 參數,或捕獲一組圓括弧內的文本;
- 字符串替代,將字符串中的某個字符替換為其它字符。
原文鏈接:
https://medium.com/factory-mind/regex-tutorial-a-simple-cheatsheet-by-examples-649dc1c3f285
【本文是51CTO專欄機構“機器之心”的原創譯文,微信公眾號“機器之心( id: almosthuman2014)”】