QWERTY

Hello World!

正規表示式簡介

簡介

  • Regular Expression, 也稱為 RegExp、regex、RE、正規表示式(台灣)、正則表達式(中國)
  • 用來處理符合某個句法規則的字串
  • 現在的標準已經被ISO(國際標準組織)批准和被Open Group組織認定(POSIX 1003.2)

用途

指定字串樣式並加以處理

  • 搜尋
  • 取出資訊
  • 取代
    • color → colour
    • 12/06/2006 → 2006-12-06
  • 檢查指定格式
    • Email格式檢查

哪些軟體使用正規表示式?

Unix like下的工具大都內建regex,Windows下的工具比較少,但也有逐漸增多的趨勢

各程式的regex雖大同小異,但仍有不同,不能直接轉換

  • unix工具: grep, sed, awk
  • 編輯器:vi, emacs, notepad++
  • 程式語言: Java, Python, Ruby

規則表

只列出常用的

位置和量詞

字元 說明 範例
^ 表示位置在開頭 ^A → 開頭為A
$ 表示位置在結尾 A$ → 結尾為A
* 比對前一個字零次或更多次 go*gle → ggle, gogle, google…
+ 比對前一個字一次或更多次 go+gle → gogle, google, gooogle…
? 比對前一個字零次或一次 go?gle → ggle, gogle
{} 表示前面的字元或集合出現的次數 c{1,3} → c, cc, ccc
c{3, } → ccc, cccc, …

集合

字元 說明 範例
[ ] 代表集合中的任一字元 [01256] → 0,1,2,5,6
- 在中括號內表示「範圍」(使用ascii計算) [0-9] → 0, 1, 2, …, 9
^ 在中括號內表示「否定」 [^aeiou] → 所有子音(❌); a, e, i, o, u以外的所有字元(✔️)
| cat|dog|bird → cat, dog, bird
  • 容許多個範圍(自動加上或):[a-zA-Z0-9]

子字串

字元 說明 範例
(x) 將x取出,拿取資料時使用 (a*) and (b*) 可找出「aaa and bb」 中的 「aaa」 和 「bb」
(?:x) 不取出x,純粹當作一個子空間使用 industr(?:y|ies) → industry, industries
(?=x) 正向肯定預查,確認後方的字串是否符合 Windows(?=95|98|NT|2000) → Windows95(✔️), Windows8(❌)
(?!x) 正向否定預查,確認後方的字串是否不符合 Windows(?!95|98|NT|2000) → Windows95(❌), Windows8(✔️)
(?<=x) 反向肯定預查,確認前方的字串是否符合 (?<=95|98|NT|2000)Windows → 95Windows(✔️), 8Windows(❌)
(?<!x) 反向否定預查,確認前方的字串是否符合 (?<!95|98|NT|2000)Windows → 95Windows(❌), 8Windows(✔️)
(?) 不貪心的比對
(不貪心:比對到的字串愈短愈好)
abc* → ab, abc, abcc… abc*? → ab, abc, abcc都只會match到ab
\1 捕獲分組 <p id="(\d*)">\1</p><p id="123">123</p>(✔️), <p id="123">1234</p>(❌)

預查即代表不對應,所以最後四個範例都只會回傳符合的Windows而非Windows95Windows8,而(?:x)是可以回傳符合的industryindustries

簡寫

字元 說明 等價表達
\d 數字 [0-9]
\D \d以外的字元 [^0-9]
\w 數字、字母、底線 [a-zA-Z0-9_]
\W \w以外的字元 [^a-zA-Z0-9_]
\s 空白字元(tab, 換行等) [ \t\n\x0B\f\r]
\S \s以外的字元 [^ \t\n\x0B\f\r]
\n 換行符號
. \n以外的字元 [^\n]
\b 英文字的邊界(空格、逗號等符號) (?<=\W)(?=\w)|(?<=\w)(?=\W)
\B \b以外的字元 (?<=\W)(?=\W)|(?<=\w)(?=\w)
\x[hex] 十六進位,其中hex是十六進位數目 \x38 → $38_{16}$ = 56
\u[unicode] unicode,其中unicode為十六進位數字 \u00A9 → ©
\c[X] 控制字元,其中 X 是控制字元 \cM 可以比對Control-M
  • 特殊字元:有特殊意義的字元,如上述*, $
    • 若要搜尋這些字元,必須在其前方加上\以跳脫字元(\^ → ^)

正規表示式範例

  • 數字或無輸入:^[0-9]*$
  • m到n個數字:^\d{m,n}$
  • 正整數(含0):^0$|^[1-9][0-9]*$
  • 用戶密碼 - 以字母開頭,長度在 6~18 之間,只能包含英數字和底線:^[a-zA-Z]\w{5,17}$
  • 漢字:[\u4e00-\u9fa5]+
  • IP位址:^((?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))*$
    • 可以先取^(\d{0,3})\.(\d{0,3})\.(\d{0,3})\.(\d{0,3})$,再判斷取出的數字在0~255之間即可
  • 可以思考下列兩題,是否有更好的寫法
    • 一個月的 31 天(包含01-09和1-31):^((0?[1-9])|((1|2)[0-9])|30|31)$
    • Email:^([a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4})*$

例:以grep搜尋檔案內容

  • 在當前目錄尋找包含輸出函式printffprintf的檔案: grep -Ern 'f?printf' .
    • -E 使用正規表示式
    • -r 遞迴搜尋(子目錄)
    • -n 列出行數
    • 加入尋找sprintf
      • grep -Ern '[sf]?printf' .

心得

  • regex 很像 CFG(Context Free Grammar),應該是可以互相轉換
  • 可先使用regex101測試regex是否正確

參考資料

  • Wikipedia
  • regexp介紹
  • 簡易圖片教學
  • regexp-轉載自張智星教學網站
  • 朱孝國–正規表示式原理及應用
  • 鳥哥
  • 洪朝貴:字串樣版 Regexp: 兼談長線學習投資
  • 常用的正規表示式
  • 学习正则表达式

歡迎關注我的其它發布管道