Perl 常用的 regexp 規則列表


我們小時候學中文, 從來就不是從文法學起, 而是聽說讀寫很多例句, 腦中自然歸納出一些 (可能自己都說不太上來的) 規則。 聽說這樣的學習方式比較自然, 效果比較好; 當然, 花費的時間也相對較長。

筆者那個年代, 英文是從國中才開始學起, 已經不像小朋友有那麼充裕的時間。 因此老師/課本/參考書免不了要幫我們整理文法以加速學習: 什麼八大詞類, 直述句/疑問句, 假設語氣, 從屬子句, ... 等等。

如果您還記得 「長線投資的電腦學習策略」 裡面提到: 今日的資訊教育實在應該以英文數學教育為師, 就能理解為什麼要談這些了。 筆者認為像是 regexp 及命令列這類東西具有長遠投資價值, 但因為要記的文字內容較多而稍嫌困難, 應該可以用學中文的方式來教/學。 所以前兩篇的重點不在有系統/有組織, 而在令讀者熟悉/培養感覺。 不過 regexp 較之中英文, 簡單很多, 如果想把重要的符號及語法用有系統/有組織的方式列出來, 其實也並不會太嚇人。 這篇的目的就是要給那些與我學英文有相同 (不太好的?) 習慣, 迫不及待想看清楚規律的讀者看的。 但請記住: 沒有看過例子的規則, 其實都不算真的學過。 所以看這篇時, 請把它當做像英文文法書一樣, 用來複習/預習/查詢, 並且在腦中多回想/設想例子; 請不要認真地死背所有規則。 有些沒有教過的東西, 後面的章節會詳述。

* * * * * * *

常用的 regexp 符號可以大致分為三類:

  1. 比對 「一個字元」 的符號:
    • [...] ... 當中任何一個字元
    • [^...] 除了 ... 之外的任何一個字元
    • . 任何一個字元
  2. 具有 「定位」 功能, 但本身不吃掉任何字元的 anchor:
    • ^... 以 ... 開頭的字串
    • ...$ 以 ... 結尾的字串
    • \b 文數字/非文數字 的邊界。
  3. 計數用, 表達 「前面的樣版重複出現多少次」 的 quantifier:
    • {5} 重複 5 次
    • {3,7} 重複 3 到 7 次
    • ? 可有可無 (0 次或 1 次)
    • * 重複出現任意次, 包含 0 次
    • + 重複出現任意次, 至少 1 次
    所謂 「前面的樣版」 可能是一個字元, 也可能是由小括弧括起來的一長串

Quantifiers 有 "不貪婪版本": 例如 +? 是 + 的 "不貪婪版"; *? 是 * 的 "不貪婪版"。

另外還有表達 「這一串」 的 (...), 及表達 「或」 的 |

* * * * * * *

我們之所以選擇 perl 來教 regexp, 有好幾個原因。 第一, perl 有一個很容易記的規則: 凡是標點符號, 加上倒斜線, 一定沒有特殊意義

第二, perl 替最常用的 [...] 定義了簡寫:

  1. \d 其實就是 [0-9], "任何一個數字"
  2. \D 其實就是 [^0-9], "任何一個非數字"
  3. \w 其實就是 [a-zA-Z0-9_], "任何一個文數字"
  4. \W 其實就是 [^a-zA-Z0-9_], "任何一個非文數字"
  5. \s 其實就是 [ \t\n], "任何一個空白類字元"
  6. \S 其實就是 [^ \t\n], "任何一個非空白類字元"

這裡有關 \w 與 \W 的說明並不嚴謹. 若要處理英文以外的西方語言, 請參考 perlre(1) 與 perllocale(1)。

第三, 請見下段。

* * * * * * *

perl 的彈性很大, 小小的變化就可以造出三種不同的句型, 應付常用的搜尋/代換工作 (實際上 一句 perl 能夠寫出的簡單變化還多得是; 不過為了怕嚇到讀者, 筆者必須克制一下, 就此打住): [圖解 'regexp 的三種常用句型']

  1. 搜尋, 並印出整列: perl -ne 'print if /.../'
  2. 搜尋, 精確列印 (不要前後文): perl -ne 'print "$1\n" if /..(..)../'
  3. 代換: perl -pe 's/.../.../g'

這裡的 $1 表示 "第一對小括弧裡面的東西", $2, $3, ... 類推。 在 "搜尋, 精確列印" 句型, 及 "代換" 句型當中, 可以用來指稱比對到的字串的一部分, 再把它的變形印出來。 例如 ip.txt 這個文字檔記錄了一些套件的大小, 類別, 名稱三個欄位的資訊。 想把第二與第三個欄位對調過來, 可以用 "搜尋, 精確列印" 句型: perl -ne 'print "$1 $3 $2\n" if /(\W+)\s+(\W+)\s+(\W+)/' ip.txt 也可以用 "代換" 句型: perl -pe 's/(\W+)\s+(\W+)\s+(\W+)/$1 $2 $3/' ip.txt 當然如果資料有點不整齊, 像 這樣, 那就只能用 "代換" 句型了。

* * * * * * *

在比對語法 m/.../ 或代換語法 s/.../.../ 後面, 都可以加上一些選項, 微調比對或代換的效果:

  1. i 忽略大小寫 (ignore)
  2. g 整列全面代換 (global)

regexp

  1. regexp
  2. 簡介
  3. 反白練習
  4. 網頁書單
  5. 誰常上機

  1. 無所不在
  2. 簡單例子
  3. 資料繪圖
  4. 網路應用
  5. 規則列表