跳轉到

1.3 正規表示式#

概念說明#

正規表示式(Regular Expression,簡稱 regex)是一種描述文字模式的迷你語言。它源自形式語言理論中的「正規語言」:任何正規表示式都等價於一個有限自動機(finite automaton),這也是為什麼它可以用極高效率進行比對。常見語法包括:

  • 字面字元:abc 比對字串 "abc"。
  • 字元類別:[abc] 比對 a、b、c 任一;[0-9] 比對數字;預設類別 \d(數字)、\w(文字字元)、\s(空白)。
  • 數量詞:*(0 次以上)、+(1 次以上)、?(0 或 1 次)、{m,n}(m 到 n 次)。
  • 錨點:^ 開頭、$ 結尾。
  • 群組與擷取:(...) 可擷取子字串供事後取用。
  • 或運算:cat|dog 比對 cat 或 dog。

正規表示式最著名的陷阱是貪婪比對:.* 會盡量多吃字元。例如對 "<a><b>" 套用 <.*> 會比對到整個字串,而 .*?(非貪婪)才會停在第一個 >。寫 regex 時務必留意。

在理論上,正規語言無法表達「對稱括號」這類需要計數的結構,因此 HTML 解析等任務不該用 regex 硬做——這是「regex 不是萬能」的經典教訓。

演算法步驟:用 regex 擷取資料#

  1. 明確列出目標文字的結構(如日期、電話、Email)。
  2. 將結構翻譯成模式,注意用非貪婪量詞與字元類別縮小範圍。
  3. 用 re.finditer 或 re.findall 掃描全文取得所有命中。
  4. 若有擷取群組,從 match 物件取出各群組內容。
  5. 用多個樣本測試,特別檢查邊界情況(空字串、特殊符號)。

Python 程式碼範例#

import re

text = """聯絡資訊:
電話 0912-345-678,市話 (02)2766-1234
Email: alice@example.com, bob@test.com.tw
日期:2026/10/18 與 2026-10-19
標籤:<a><b>文字</b></a>
"""

# 1) 手機號碼:\d 代表數字
print(re.findall(r'09\d{2}-\d{3}-\d{3}', text))
# ['0912-345-678']

# 2) Email 擷取(含群組)
for m in re.finditer(r'([\w.]+)@([\w.]+)', text):
    print(m.group(0), '=> 帳號:', m.group(1), '網域:', m.group(2))

# 3) 貪婪 vs 非貪婪
print(re.findall(r'<.*>', text))     # ['<a><b>文字</b></a>']
print(re.findall(r'<.*?>', text))    # ['<a>', '<b>', '</b>', '</a>']

# 4) 日期兩種格式:| 連接分支
print(re.findall(r'\d{4}[/\-]\d{2}[/\-]\d{2}', text))

# 5) sub:遮蔽電話中間三碼
print(re.sub(r'(09\d{2})-\d{3}(-\d{3})', r'\1-***\2', text))

# 6) 中文字元類別(Unicode 範圍)
print(re.findall(r'[\u4e00-\u9fff]+', text))

# 7) split:以逗號與空白切分
print(re.split(r'[,,、\s]+', '蘋果, 香蕉、鳳梨 芒果'))

複雜度分析#

比對長度 n 的文字與長度 m 的模式:基於有限自動機(NFA 模擬或 DFA)的引擎,時間為 O(n·m) 或建好 DFA 後 O(n),且不會發生災難性回溯(catastrophic backtracking)。Python 的 re 採用回溯法,多數實用模式為線性,但像 (a+)+b 這類巢狀量詞模式在不可能比對成功時,可能退化到指數時間——這是「正規表示式阻斷服務(ReDoS)」攻擊的根源。撰寫模式時應避免巢狀不定量詞,或改用非回溯引擎(如 Rust 的 regex crate、Google RE2)。

練習#

  1. 寫出一個比對台灣身分證字號(一個大寫英文字母加 9 位數字)的模式,並測試 A123456789。
  2. 寫一個模式,找出文字中所有「以西元 19xx 或 20xx 開頭的年份」,並說明你如何避免比對到 20261 這種錯誤年份(提示:使用邊界條件 (?!\d))。
  3. 對模式 (x+x+)+y 在字串 "xxxxxxxxxxxxxxxxxxxxxxxx"(不含 y)上執行 re.match 並計時,觀察回溯造成的時間爆炸。