正則表達式入門 — 一個通過例子來說明的備忘單

  • 2019 年 11 月 26 日
  • 筆記

正則表達式(regex 或 regexp)在通過搜索特定搜索模式的一個或多個匹配(即 ASCII 或 unicode 字符的特定序列)從任何文本中提取信息時非常有用。

應用領域從驗證到解析/替換字符串,將數據轉換為其他格式以及網絡爬蟲。

最有趣的功能之一是,一旦你學會了語法,你就可以在(幾乎)所有編程語言中使用這個工具(JavaScript,Java,VB,C#,C / C ++,Python,Perl,Ruby,Delphi,R,Tcl等等),對引擎支持的最高級功能和語法版本的支持有一點區別)。

讓我們首先看一些例子和解釋。

基本知識點

錨 — ^ 以及 $

The      匹配任意字符串以 The 為開頭-> **[試一下!](https://regex101.com/r/cO8lqs/2)**    end$       匹配任意字符串以 end 為結尾    ^The end$    匹配字符串的(開頭和結尾分別是 The end)    roar       匹配任意具有 roar 的字符串

量詞 — * + ? 以及 {}

abc*       匹配一個字符串具有 ab 其後有0個或者多個 c->[試一下!](https://regex101.com/r/cO8lqs/1)    abc+       匹配一個字符串具有 ab 其後有1個或者多個 c    abc?       匹配一個字符串具有 ab 其後有0個或者1個 c    abc{2}     匹配一個字符串具有 ab 其後有2個 c    abc{2,}    匹配一個字符串具有 ab 其後有2個或者多個 c    abc{2,5}   匹配一個字符串具有 ab 其後有2到5個 c    a(bc)*       匹配一個字符串具有 a 其後有0到多個 bc 的副本    a(bc){2,5}   匹配一個字符串具有 a 其後有0到5個 bc 的副本

OR 操作符 — | 或 []

a(b|c)     匹配一個字符串具有 a 其後有 b 或者 c -> [試一下!](https://regex101.com/r/cO8lqs/3)    a[bc]      與上一條相同

字符類 — d w s 以及 .

d         匹配一個數字字符-> [試一下!](https://regex101.com/r/cO8lqs/4)    w         匹配一個單詞字符(字母以及下劃線) -> [試一下!](https://regex101.com/r/cO8lqs/4)    s         匹配空白字符(包括 tab 以及換行)    .          匹配任意字符->[試一下!](https://regex101.com/r/cO8lqs/5)

仔細使用 . 操作符,因為類或者否定類字符(我們在下面會提到)將會更快更準確。

d, w 以及 s 分別對應其否定類 D, W 以及 S

例如, D 將執行與 d 獲得的相反的匹配。

D         匹配一個非數字字符->[試一下!](https://regex101.com/r/cO8lqs/6)

為了獲取字面上疑似的字符,你必須使用反斜杠 來轉義字符 ^.[$()|*+?{,因為它們具有特殊含義。

$d*       匹配一個字符具有一個數字字符其前面是一個 $>[試一下!](https://regex101.com/r/cO8lqs/9)

注意你也可以匹配非打印字符比如 tabs t,換行 n,回車 r

標誌

我們正在學習如何構建一個正則表達式但是卻忘記了一個基礎的概念:標誌

一個正則表達式的格式通常是這個樣子的 /abc/,搜索模式通過兩個斜杠符 / 進行區分。在末尾我們可以規定一個標誌使用以下的值(我們也可以將它們相互結合):

  • g(全局的) 在第一匹配之後不會立即返回,從前面匹配之後繼續搜索
  • m (多行的) 當使用 ^ 以及 $ 的時候將會匹配行首和行尾而不是整個字符串
  • i (大小寫不敏感的) 讓整個表達式大小寫不敏感(比如 /aBc/i 將匹配 Abc

中級知識點

分組以及捕獲 — ()

a(bc)           括號產生一個值為 bc 的捕獲分組-> [試一下!](https://regex101.com/r/cO8lqs/11)    a(?:bc)*        我么可以使用 ?:  讓捕獲分組不起作用->[試一下!](https://regex101.com/r/cO8lqs/12)    a(?<foo>bc)     我們可以使用 ?<foo> 將名字放在分組中 -> [試一下!](https://regex101.com/r/cO8lqs/17)

當我們需要使用你首選的編程語言從字符串或數據中提取信息時,此運算符非常有用。 由幾個組捕獲的任何多次出現都將以經典數組的形式公開:我們將使用匹配結果的索引來訪問它們的值。

如果我們選擇為組添加名稱(使用( ?<foo> …)),我們將能夠使用匹配結果檢索組值,如字典,其中字典的名稱就是剛才添加的名稱。

方括號表達式 — []

[abc]            匹配一個具有 要麼一個 a 或者一個 b 或者一個 c 的字符串-> 等同於 `a|b|c`-> [試一下!](https://regex101.com/r/cO8lqs/7)    [a-c]            與前一條相同    [a-fA-F0-9]      字符串代表一個十六進制數,大小寫不敏感-> [試一下!](https://regex101.com/r/cO8lqs/22)    [0-9]%           一個具有從0到9其後後一個 % 符號    [^a-zA-Z]         一個不是大小寫字母的字符串。在這種情況下,^ 被用為 表達式的否定。->[試一下!](https://regex101.com/r/cO8lqs/10)

請記住,在括號內表達式中,所有特殊字符(包括反斜杠)都會失去它們的特殊功能:因此我們不會應用「轉義規則」。

貪婪和惰性匹配

量詞 ( *+{}) 是貪婪操作符, 所以他們儘可能地通過提供的文本擴展匹配.

比如, <.+> 會從 Thisisa**<div>simple div</div>**test 中匹配 <div>simple div</div>。 為了僅僅匹配 div 標籤, 我們可以使用一個 ? 讓它變為惰性:

<.+?>            匹配 任意字符被包含在 < 以及 >之中,出現一到多次, 需要的時候才會擴展-> [試一下!](https://regex101.com/r/cO8lqs/24)

注意更好的解決方案是避免使用 .來構建一個更嚴格的正則表達式: <[^<>]+> 匹配任意的字符除了 < 或者 > 一次或者多次被包含在 < 以及 > 之中-> 試一下!

高級知識點

邊界 — b 以及 B

babcb        執行「僅限整個單詞」搜索->[試一下!](https://regex101.com/r/cO8lqs/25)

b 代表一個錨類似於符號 (等同於 $ 以及 ^) 的匹配位置, 其中一側是單詞字符(如 w),另外一側不是單詞字符(例如它可能是字符串的開頭或空格字符)。

隨之而來是它的否定, B. 這將會匹配所有 b 不會匹配的位置如果我們希望搜索模式可以被單詞字符所匹配。

BabcB          僅在搜索模式被單詞字符包圍的時候才會匹配 -> [試一下!](https://regex101.com/r/cO8lqs/26)

返回引用— 1

([abc])1              使用 `1` 將會匹配與第一個捕獲分組相同的文本 -> [試一下!](https://regex101.com/r/cO8lqs/14)    ([abc])([de])21      我們可以使用 2 (3, 4, 等等)來獲取被第二個(第三個, 第四個, 等等.)捕獲分組相同的文本 -> [試一下!](https://regex101.com/r/cO8lqs/15)    (?<foo>[abc])k<foo>   我們將分組名稱命名為`foo` 並隨後使用 `(k<foo>)` 來進行引用。結果與第一個正則表達式相同 -> [試一下!](https://regex101.com/r/cO8lqs/16)

前瞻和後瞻 — (?=) 以及 (?<=)

d(?=r)       匹配一個 `d` 並且其後有一個 `r`, 但是 `r` 將不會是整個正則表達式匹配的一部分-> [試一下!](https://regex101.com/r/cO8lqs/18)    (?<=r)d      匹配一個 `d` 並且前面有一個 `r`, 但是 `r` 將不會是整個正則表達式匹配的一部分-> [試一下!](https://regex101.com/r/cO8lqs/19)

我們也可以使用否定符號 !

d(?!r)         匹配一個 `d` 並且其後不是一個 `r`, 但是 `r` 將不會是整個正則表達式匹配的一部分-> [試一下!](https://regex101.com/r/cO8lqs/20)    (?<!r)d        匹配一個 `d` 並且前面不是一個 `r`, 但是 `r` 將不會是整個正則表達式匹配的一部分-> [試一下!](https://regex101.com/r/cO8lqs/21)

總結

正如你所見,正則表達式的應用程序字段可以是多個,我確信你已經認識到在開發人員職業生涯中看到的這些任務中的至少一個,這裡有一個快速列表:

  • 數據驗證 (比如檢查一個時間字符串 i 的格式是正確的)
  • 數據抓取(特別是網頁抓取,最終按特定順序查找包含特定單詞集的所有頁面)
  • 數據轉換(將數據從「原始」轉換為另一種格式)
  • 字符串解析(例如捕獲所有URL GET參數,捕獲一組括號內的文本
  • 字符串替換(即使在使用通用 IDE 的代碼會話期間,例如在相應的 JSON 對象中轉換 Java 或 C# 類 – 將「;」替換為「,」將其設為小寫,避免類型聲明等)
  • 語法高亮,文件重命名,數據包嗅探和涉及字符串的許多其他應用程序(其中數據不必是文本)