電話號碼有「138-1234-5678」,有「138 1234 5678」,還有一次寫成了一首小詩。模式能把它們都找出來,按空格切分做不到。正規到底捕獲了什麼?
正規表達式描述一種文字模式。Python 的 re 模組可以尋找第一個比對、收集全部比對,或替換比對到的文字。模式先用原始字串,例如 r"\d+",這樣反斜槓會原樣交給正規引擎。 你還會區分 match、search 和 fullmatch,解析命名群組,並跳脫常值。
尋找第一個比對
re.search 回傳模式第一次出現處的比對物件;沒有比對時回傳 None。用 group() 讀取比對到的文字。真實程式裡一定要處理 None 的情況。
import re
match = re.search(r"\d+", "Order 42 is ready")
print(match.group())第一個數字
找出所有比對
re.findall 回傳所有不重疊比對組成的列表。字元類 [A-Z] 比對一個大寫字母;量詞 + 表示一次或多次。結果可以直接計數或拼接。
import re
print(re.findall(r"\d+", "a1 b22 c333"))
print(re.findall(r"[A-Z]", "PyTHON"))所有比對片段
替換比對文字
re.sub 會把每個比對替換成指定字串。這裡的 \s+ 表示一個或多個空白字元,所以連續空格會合併成一個。模式用原始字串,並先在小樣本上測試替換結果。
import re
text = "latte tea mocha"
print(re.sub(r"\s+", " ", text))規範化空白
match、search 與 fullmatch
match() 從開頭錨定;search() 掃描任意位置;fullmatch() 要求整個字串都比對。選擇能表達規則的最弱工具。None 是正常結果,呼叫 group() 前先檢查。
import re
text = "order 42 ready"
print(bool(re.match(r"\d+", text)))
print(bool(re.search(r"\d+", text)))
print(bool(re.fullmatch(r"\d+", "42")))
print(re.search(r"\d+", text).group())前綴、任意位置,還是整個欄位
命名群組解析記錄
命名群組讓模式更可讀,也能直接回傳字典。把嚴格形狀寫進模式,再按名字讀取欄位。呼叫 groupdict() 前檢查 None;比對失敗不等於空記錄。
import re
pattern = re.compile(r"(?P<date>\d{4}-\d{2}-\d{2})\|(?P<drink>[a-z]+)\|(?P<price>\d+\.\d{2})")
match = pattern.fullmatch("2026-10-28|latte|4.50")
print(match.groupdict() if match else "invalid")
bad = pattern.fullmatch("2026-10-28|latte|free")
print(bad is None)嚴格形狀,可讀欄位
跳脫常值,提防貪婪
re.escape() 讓使用者文字可以安全嵌入模式。貪婪量詞會儘量多取;在量詞後加問號會變成惰性。模式越窄越好,並且同時用有效和無效樣本測試。
import re
needle = "a.b"
text = "a.b axb"
print(re.findall(re.escape(needle), text))
html = "<b>bold</b>"
print(re.findall(r"<.+?>", html))
print(re.findall(r"<.+>", html))跳脫文字;惰性不一定更好
本課要點
- 正規模式優先使用原始字串。
- re.search 回傳第一個比對或 None。
- re.findall 回傳所有比對組成的列表。
- re.sub 會替換文字中所有比對部分。
- 整欄位驗證用 fullmatch,找出現用 search,常值文字先 re.escape。
常見錯誤
- 忘記 r 前綴,讓 Python 先解釋反斜槓。
- search 回傳 None 時仍然呼叫 group()。
- 模式範圍過寬,比對到了並不想要的文字。
- 直接拼接未跳脫的使用者輸入來構造模式。
從 "a1 b22 c333" 中提取所有數字,再用逗號連接結果。
動手試試
改改變數、先預測輸出,再執行程式碼。第一次點擊「執行程式碼」時會下載 Python 執行時,可能需要幾秒鐘。
練習本課
12 道題,作答後立即看到解釋。