Regexp 是什麼東東?

Regular Expression (簡稱 regexp 或 RE) 是什麼? 有人直譯為「常規表示式」; 筆者偏好意譯, 姑且叫它「字串樣版」。 Regexp 是一組大約三四十個特殊符號 ( 完整文件), 只要學會其中常用二十來個, 就能搜尋字串/代換字串, 甚至完成許多滑鼠選單做不到的驚奇繁雜工作。 以下舉一些例子; 為讓您專注於 regexp 本身, 暫時不寫出完整的指令, 只寫出指令中關於 regexp 的那一小段。

  1. 英文的 "顏色" 一字, 有兩種拼法: color 及 colour。 用 regexp 表達, 可以一石兩鳥: colou?r 其中的 ? 表示 「前面的字元可有可無」
  2. 想要找 "port" 與 "ports", 但又不希望找到 "export", "portable", "important" 等等一大堆不相關的單字, 該怎麼辦? 用 \bports?\b 這裡的 \b 表示 「(文數字 vs. 標點符號等等其他字元 之間的) 邊界 (boundary); 旁邊不可有其他文數字」。 所謂文數字, 就是英文字母, 數字, 及底線 "_"。
  3. 在一篇文章當中, 抓出所有 「看起來像是機場代碼的字串」 (例如 TPE 臺北, KHH 高雄, LAX 洛杉磯, ... 等等): \b[A-Z][A-Z][A-Z]\b。 這裡的 [A-Z][ABCDEFGHIJKLMNOPQRSTUVWXYZ] 的簡寫, 意思是 「任何一個大寫字母」
  4. 如何在一大片文字, 銀行帳號, 信用卡號... 當中, 找出看來像是行動電話號碼的字串, 例如 0912345678 或是 0912-345678 或是 0912-345-678 之類的? 09\d\d-?\d\d\d-?\d\d\d 這裡的 \d[0-9] 的簡寫, 這又是 [0123456789] 的簡寫, 意思是 「任何一個數字字元」
  5. 想要找一組數字 ip (例如 168.95.1.1 或 163.17.9.176 之類的) 印象中在某個檔案內曾看過, 但既不記得精確的數字, 也不記得在那個檔案看過, 該怎麼辦? 可以搜尋 \d+\.\d+\.\d+\.\d+ 抓出所有數字 ip。 這裡的 + 表示 「前面的東西, 可以重複出現 1 次, 2 次, 3 次, ... 任意次」。 因為 . 在 regexp 當中有特殊的意義: 「任何一個字元」; 但在這裡我們就是要找 "." 於是在前面加上 \ 以取消它的特殊意義。
  6. 可以把一個文字檔裡面的所有空白列都刪掉嗎? 這個 regexp 可以抓出所有空白列: ^\s*$。 在 regexp 最前面放一個 ^ 表示您只對 「出現在一列之首」 的樣版有興趣; 在 regexp 的最後面放一個 $ 表示您只對 「出現在一列之尾」 的樣版有興趣。 \s 是 [ \t\n] 的簡寫, 意思是 「任何一個空白字元」 (包含空格, tab, 等等)。 * 表示 「前面的東西, 可以重複出現 0 次, 1 次, 2 次, ... 任意次」。 這個樣版翻譯成中文, 就是 「從頭到尾都是一片空白的那種列」。

恭喜! 您已經學會大約十個 regexp 特殊符號。 Regexp 總共大約有三四十個符號; 不過其中大約有一半較少用; 只要熟用兩打, 就已經可以變很多魔術了。 你不只可以在 linux 命令列上使用 regexp, 還有 vim (及其他各種) 編輯器、 各種程式語言 (perl/python/php/ruby/javascript/C/C++/...)、 ... 等等許多環境裡面也都可以使用。 Regexp 是一種超級低成本, 高報酬的學習投資。 這也是為什麼我把 regexp 列為 推薦 「實用到二十二世紀」 的程式語言 的第一名。 耐心把這份講義看一半, 絕對比花時間學花俏的圖形介面軟體更值回票價。

你可先拿 假面電話簿 去練習。 (若出現亂碼, 請在瀏覽器裡 「檢視」=> 「編碼」=>「unicode」) 把這個檔案或是你自己想搜尋的文字檔案內容剪貼到 RegExrregex101rubular 其中任何一個網站上, 然後在最上方試打各種 regexp, 讓各個欄位被標示出來。 提醒: 別貼隱私或機密文件內容!

能夠讓有興趣的字串被標示出來很有趣; 但若真的要能夠做一些有用的事, 那就需要命令列了。 請從 幾條不同的 linux 入門路徑 當中挑一個方法安裝、 進入 linux、 從選單當中找到終端機、 看著檔案總管截圖快學基本指令。 接下來的操作都在 linux 底下執行。

其他有趣的連結:

  1. Regex Cross­word
  2. 用十分鐘學會字串處理的那些事兒 (陳鐘誠老師)