Python 正規表達式 (Regex)

Python 的 re 模組提供了對正規表達式 (Regular Expression) 的支援。正規表達式是一種強大的文字搜尋和處理工具。

本篇專注於 Python re 模組的用法。關於正規表達式的詳細語法(如符號意義),請參考 正規表達式教學

常用函數

要使用正規表達式,首先匯入模組:

import re

re.search() - 搜尋第一個相符

搜尋字串中「任意位置」的第一個相符項目。

text = "The price is $99.99"
match = re.search(r'\$\d+\.\d+', text)

if match:
    print("Found:", match.group())  # Found: $99.99
    print("Index:", match.span())   # Index: (13, 19)
else:
    print("Not found")

re.match() - 從頭開始比對

只檢查字串的 開頭 是否符合。

text = "The price is $99.99"

# 失敗,因為開頭是 "The" 不是數字
print(re.match(r'\d+', text))  # None

# 成功
print(re.match(r'The', text))  # <re.Match object; span=(0, 3), match='The'>

re.findall() - 搜尋所有相符

回傳所有相符項目的字串列表 (List)。

text = "Apple: 10, Banana: 20, Orange: 30"
numbers = re.findall(r'\d+', text)

print(numbers)  # ['10', '20', '30']

re.sub() - 取代

將符合樣式的部分取代為其他字串。

text = "User: private@example.com, Admin: root@example.com"
# 將 email 隱藏
result = re.sub(r'[\w\.-]+@[\w\.-]+', '***', text)

print(result)
# User: ***, Admin: ***

Match 物件

searchmatch 成功時,回傳一個 Match 物件:

text = "My email is alice@example.com"
match = re.search(r'(\w+)@(\w+\.com)', text)

if match:
    print(match.group())    # 完整相符: alice@example.com
    print(match.group(1))   # 第一個群組: alice
    print(match.group(2))   # 第二個群組: example.com
    print(match.groups())   # 所有群組: ('alice', 'example.com')

編譯正規表達式

如果你需要在迴圈中重複使用同一個樣式,建議使用 re.compile() 預先編譯,效能會更好。

# 編譯樣式
email_pattern = re.compile(r'[\w\.-]+@[\w\.-]+')

users = [
    "user1@example.com",
    "invalid-email",
    "user2@test.org"
]

for user in users:
    if email_pattern.match(user):
        print(f"Valid: {user}")
    else:
        print(f"Invalid: {user}")

常用 Flags

可以使用 Flags 改變比對行為:

  • re.IGNORECASE (re.I): 忽略大小寫
  • re.MULTILINE (re.M): 多行模式,影響 ^$ 的行為
  • re.DOTALL (re.S): 讓 . 也可以比對換行符號
text = """Line 1
Line 2"""

# 預設 . 不包含換行
print(re.findall(r'Line 1.Line 2', text))  # []

# 使用 DOTALL
print(re.findall(r'Line 1.Line 2', text, re.DOTALL))  # ['Line 1\nLine 2']

# 忽略大小寫
print(re.findall(r'line', "Line line LINE", re.IGNORECASE))  # ['Line', 'line', 'LINE']

分組與命名

使用 (?P<name>...) 可以為群組命名,讓程式碼更易讀:

pattern = r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})'
match = re.search(pattern, "2024-12-25")

if match:
    print(match.group("year"))   # 2024
    print(match.group("month"))  # 12
    print(match.group("day"))    # 25