正規表示式 (Regular Expression) 語法整理
正規表示式 (Regular Expression, 簡寫 regex、regexp 或 RE) 是用於字串比對的小型語言,又稱正則表達式、正規表示法、規則運算式、常規表示法 (Wiki)。
很多程式語言和軟體都會附加「正規表示式」這項功能。在字串的處理上,針對大量、重複、有固定邏輯的文字,正規表示式是非常強而有力的工具! 即便不是程式設計師,在可以在運用到正規表示式的場合 (例如: 文字編輯器),能幫你節省許多文字處理的時間。但是不同的軟體所附加的正規表示式可能略有差異,這部份就要稍加留意。
不過在初學者的眼中,正規表示式卻又像是天書一樣的難以理解。以下文章針對正規表示式的相關語法做解說,你可到線上測試工具,以實際的例子去做測試。
語法整理 (Pattern)
字元符號
- .: 任意文字、數字及符號,但不包括換行
- \d: 任意數字 (同 [0-9])
- \w: 任意文字、數字或底線 (同 [0-9a-zA-Z_])
- \s: 任意空白字元,包含空白、定位、換行字元 (同 [ \t\n])
- \D: 任意非數字
- \W: 任意非文字、數字或底線
- \S: 任意非空白字元 (同 [^ \t\n])
- \n: 換行字元
- \t: 定位字元
-
\OCT: 八進制字元,ex: \101 = "A"
-
\xHEX: 十六進制字元,ex: \x41 = "A"
- \uUnicode: Unicode 字元,ex: \u4F60 = "你"。
另外,Unicode 中文範圍: [\u4E00-\u9FA5],中日韓文字範圍: [\u4E00-\u9FFF] - \: 不轉譯控制符號
一般狀態下,字元符號都不包括換行字元 (\n),因此遇到「換行」就會停止比對。在某些環境下可以啟用多行模式 (Multiline),則換行字元 (\n) 會被視為一般文字。
字元列舉
列舉的原則:
- 放在中括號 [ ... ] 裡的字元皆為單獨比對的字元
- 在中括號內加 ^ 表示「反向列舉」
- 可以用 - 來代表連續的字元範圍
範例:
- [0123456789]: 任意數字 (同 \d)
- [0-9]: 任意數字,同 (同 \d)
- [a-z]: 任意小寫英文字母
- [a-zA-Z]: 任意大小寫的英文字母
- [0-9a-zA-Z]: 任意數字、英文字母
- [^x]: 反向列舉,任意非 x 的字元
- [^0-9]: 反向列舉,任意非數字 (同 \D)
字串列舉
- |: 或
次數符號、限定符號
- *: 重複 0 次以上 (同 {0,}) *貪婪原則
- +: 重複 1 次以上 (同 {1,}) *貪婪原則
- ?: 重複 0 或 1 次 (同 {0,1}) *貪婪原則
- {n}: 重覆 n 次
- {n,}: 重覆 n 次以上 *貪婪原則
- {0,n}: 重覆 0 ~ n 次 *貪婪原則
- {n,m}: 重覆 n ~ m 次 *貪婪原則
說明:
- 所有的「次數符號」都會極大化 (Infinite) 要比對的範圍,稱為「貪婪原則」。
ex: .*\d+ 因為貪婪原則,前面的 .* 就已經涵蓋後面的 \d+ 所要比對的數字了,因此 \d+ 在這裡是多餘的! - 如果要取消「貪婪原則」,只要在次數符號的後面加上 ? 即可讓它節制一點、不要那麼的貪婪,讓放在後面的比對規則也可以有作用。因此,上面的範例就變成: .*?\d+。
- 在實務上,我們不太會將 * 與 ? 這兩個次數符號放在正規表示式的最後,因為它們兩者都允許「重覆 0 次」,因為比對之後可能會多出「空白」的結果。
邊界符號
- ^: 要在行的開頭 (Start of line)
- $: 要在行的結尾 (End of line)
- \b: 必須是單詞 (文字、數字、底線) 的開頭或結尾
- \B: 不能是單詞 (文字、數字、底線) 的開頭或結尾
進階
群組
- 可以使用小括號 ( ... ) 將既有的規則組合成一個「群組」
- 建立規則群組之後,可再以此群組為基礎,套用其它的規則
- 可以用 \1 ... \9 來代表前面符合的群組
- 當要儲存或取代比對的內容時,可以用 $1 .. $9 (或 \1 ... \9) 來代表各群組
判斷式
右合、正看 (Lookahead):
-
Pattern1(?:Pattern2): 符合 Pattern1 並且右方符合 Pattern2 才算符合全部的 Patternex: Windows(?:95|98|2000) 可符合 Windows95,但不符合 WindowsNT
-
Pattern1(?=Pattern2): 符合 Pattern1 並且右方符合 Pattern2 才算符合 Pattern1
白話文: 我要找 Pattern1,其右方必須為 Pattern2ex: Windows(?=95|98|2000) 可符合 Windows95 的 Windows,但不符合 WindowsNT 的 Windows -
Pattern1(?!Pattern2): 符合 Pattern1 但右方不符合 Pattern2 才算符合 Pattern1
白話文: 我要找 Pattern1,但右方不能為 Pattern2ex: Windows(?!95|98|2000) 可符合 Widnows 或 WindowsNT 的 Windows,但不符合 Windows95 的 Windows
左合、回頭看 (Lookbehind):
- (?<=Pattern1)Pattern2: 符合 Pattern2 並且左方符合 Pattern1 才算符合 Pattern2
白話文: 我要找 Pattern2,其左方必須為 Pattern1
ex: (?<=Chapter|Section)[\d]+ 可符合 Chapter15 的 15,但不符合 Topic15 的 15 - (?<!Pattern1)Pattern2: 符合 Pattern2 但左方不符合 Pattern1 才算符合 Pattern2
白話文: 我要找 Pattern2,但左方不能為 Pattern1
ex: (?<!Chapter|Section)(?<!\d)[\d]+ 可符合 Topic15 的 15,但不符合 Chapter15 的 15
說明:
- 以上判斷式的小括號 (? ... ) 並不會成為「群組」
- 並非所有的環境都能完整支援判斷式的用法
線上測試
- Regular Expressions 101
- RegEx Testing
- 正規表示式線上測試-站長工具
- Regulex: JavaScript Regular Expression Visualizer - 將正規表示式圖形化
- Regexper - 將正規表示式圖形化
- 編程膠囊 - 教學與題目練習
- RegexOne - 題目練習
No comments yet.