Python 正規表達式(Python Regex)
這篇 Python 正規表達式教學將帶你用「模式」描述文字:找出所有 Email、驗證手機號碼格式、批次取代——字串方法做不到的模糊比對,正規表達式(regex)都能做。內建 re 模組就夠用。
先記住一個鐵則:regex 模式一律寫成 raw string(r"..."),避免反斜線被 Python 先吃掉一層。
常用語法速查
| 語法 | 意義 | 範例 |
|---|---|---|
\d | 一個數字 | \d\d 配兩位數 |
\w | 字母、數字、底線 | |
\s | 空白字元 | |
. | 任意一個字元 | |
+ | 前面的東西 1 次以上 | \d+ 一串數字 |
* | 0 次以上 | |
? | 0 或 1 次 | |
{n} | 恰好 n 次 | \d{4} 四位數 |
[abc] | a 或 b 或 c | [0-9] 同 \d |
^ / $ | 開頭/結尾 | |
() | 分組擷取 |
re 的四個主力函式
| 函式 | 用途 | 回傳 |
|---|---|---|
re.search(p, s) | 找第一個符合 | Match 物件或 None |
re.findall(p, s) | 找出全部 | List |
re.sub(p, new, s) | 取代 | 新字串 |
re.match(p, s) | 只從開頭比對 | Match 物件或 None |
import re
text = "訂單編號 A123 與 B456 已出貨"
m = re.search(r"[A-Z]\d{3}", text)
print(m.group()) # 第一個符合
print(re.findall(r"[A-Z]\d{3}", text)) # 全部
print(re.sub(r"\d", "*", text)) # 數字遮罩
執行輸出:
A123
['A123', 'B456']
訂單編號 A*** 與 B*** 已出貨
實戰一:擷取 Email
import re
text = "聯絡方式:alice@test.com 或 bob.chen@company.com.tw"
emails = re.findall(r"[\w.]+@[\w.]+\.\w+", text)
print(emails)
執行輸出:
['alice@test.com', 'bob.chen@company.com.tw']
實戰二:驗證台灣手機號碼
台灣手機是 09 開頭共 10 碼。驗證「整個字串」要用 ^...$ 鎖頭尾:
import re
def is_phone(s):
return re.search(r"^09\d{8}$", s) is not None
print(is_phone("0912345678"))
print(is_phone("0912-345-678")) # 有橫線,不符
print(is_phone("091234567")) # 只有 9 碼
執行輸出:
True
False
False
要接受橫線格式,模式改成 r"^09\d{2}-?\d{3}-?\d{3}$"(-? 表示橫線可有可無)。
分組擷取:()
用括號把想要的部分框起來,group(1)、group(2) 分別取出:
import re
log = "2026-06-05 14:30 ERROR 資料庫連線逾時"
m = re.search(r"(\d{4}-\d{2}-\d{2}) \d{2}:\d{2} (\w+)", log)
if m:
print("日期:", m.group(1))
print("等級:", m.group(2))
執行輸出:
日期: 2026-06-05
等級: ERROR
常見錯誤
1. 忘記 raw string
"\d" 在一般字串裡有時能動、有時不能(如 \b 會變成退格字元),錯起來極難查。模式永遠寫 r"...",不用記哪些字元有問題。
2. match 與 search 搞混
re.match 只從字串「開頭」比對,目標在中間就回 None。日常九成情況用 search 或 findall。
3. AttributeError: ‘NoneType’ object has no attribute ‘group’
search 沒找到回傳 None,直接 .group() 就爆炸。先檢查:if m: 再取值。
4. .* 貪婪比對抓太多
.* 會盡量吃到最長;想要「最短符合」用 .*?。例如從 <b>A</b><b>B</b> 抓標籤內容,<b>(.*)</b> 會抓到 A</b><b>B,<b>(.*?)</b> 才是 A 與 B。
總結
模式一律 r"...";四主力 search(找一個)、findall(找全部)、sub(取代)、match(限開頭);驗證整串鎖 ^...$、擷取局部用 () 分組;search 回 None 先判斷再 group。正規表達式語法是跨語言通用的,學一次到處用。下一篇是第四階段壓軸:Generator 與 Decorator。