正規表達式
Python 的 `re` 模組(regular expression,正規表達式)可用來搜尋、比對及擷取字串中的特定格式。
## 1. 匯入 `re` 模組
```python
import re
```
正規表達式通常使用「原始字串」表示法 `r"..."`,可避免反斜線 `\` 被 Python 先解讀。
例如:
```python
pattern = r"\d+"
```
其中:
- `\d`:一個數字,等同於 `[0-9]`
- `+`:前面的規則出現一次以上
- `*`:出現零次以上
- `?`:出現零次或一次
- `{n}`:剛好出現 `n` 次
- `{n,m}`:出現 `n` 到 `m` 次
- `^`:字串開頭
- `$`:字串結尾
- `[...]`:字元集合
- `(...)`:群組
- `|`:或
---
## 2. 常用的比對方法
### `re.match()`
從字串開頭開始比對:
```python
result = re.match(r"\d+", "123abc")
if result:
print("比對成功")
print(result.group()) # 123
```
### `re.search()`
搜尋字串中是否存在符合的內容:
```python
result = re.search(r"\d+", "abc123xyz")
if result:
print(result.group()) # 123
```
### `re.fullmatch()`
要求整個字串完全符合正規表達式,適合驗證手機號碼或 Email:
```python
result = re.fullmatch(r"\d{3}", "123")
if result:
print("整個字串符合")
```
### `re.findall()`
找出所有符合的內容:
```python
numbers = re.findall(r"\d+", "電話 0912345678,分機 123")
print(numbers)
# ['0912345678', '123']
```
---
# 3. 台灣手機號碼格式比對
一般台灣手機號碼格式為:
```text
09xxxxxxxx
```
也就是:
- 開頭為 `09`
- 後面再接 8 個數字
- 總長度為 10 位數
正規表達式:
```python
r"09\d{8}"
```
但若要驗證「整個字串」必須是手機號碼,建議使用 `fullmatch()`:
```python
import re
pattern = r"09\d{8}"
phone_numbers = [
"0912345678",
"0987654321",
"091234567", # 少一碼
"0812345678", # 不是 09 開頭
"09-1234-5678" # 含有連字號
]
for phone in phone_numbers:
if re.fullmatch(pattern, phone):
print(phone, "格式正確")
else:
print(phone, "格式錯誤")
```
輸出:
```text
0912345678 格式正確
0987654321 格式正確
091234567 格式錯誤
0812345678 格式錯誤
09-1234-5678 格式錯誤
```
## 支援連字號或空白
如果也允許以下格式:
```text
0912-345-678
0912 345 678
```
可以使用:
```python
pattern = r"09\d{2}[- ]?\d{3}[- ]?\d{3}"
```
完整範例:
```python
phone_numbers = [
"0912345678",
"0912-345-678",
"0912 345 678",
"0912_345_678"
]
for phone in phone_numbers:
if re.fullmatch(r"09\d{2}[- ]?\d{3}[- ]?\d{3}", phone):
print(phone, "格式正確")
else:
print(phone, "格式錯誤")
```
其中:
```python
[- ]?
```
表示連字號或空白可以出現一次,也可以不出現。
## 支援國際格式
若要接受:
```text
+886912345678
+886 912345678
```
可以寫成:
```python
pattern = r"(?:09\d{8}|\+886 ?9\d{8})"
```
範例:
```python
phones = [
"0912345678",
"+886912345678",
"+886 912345678",
"886912345678"
]
for phone in phones:
if re.fullmatch(r"(?:09\d{8}|\+886 ?9\d{8})", phone):
print(phone, "格式正確")
else:
print(phone, "格式錯誤")
```
說明:
- `(?:...)`:非捕獲群組
- `|`:表示二選一
- `\+`:比對真正的 `+` 字元,因為 `+` 在正規表達式中本身具有特殊意義
---
# 4. Email 格式比對
Email 常見格式如下:
```text
username@example.com
```
可以使用一個簡單且實用的正規表達式:
```python
r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$"
```
拆解如下:
```text
^
[A-Za-z0-9._%+-]+
@
[A-Za-z0-9.-]+
\.
[A-Za-z]{2,}
$
```
說明:
- `^`:從字串開頭開始
- `[A-Za-z0-9._%+-]+`:Email 帳號部分,可包含英文字母、數字及部分符號
- `@`:必須有 `@`
- `[A-Za-z0-9.-]+`:網域名稱
- `\.`:真正的句點 `.`
- `[A-Za-z]{2,}`:網域後綴至少兩個英文字母,例如 `com`、`tw`
- `$`:到字串結尾為止
範例:
```python
import re
email_pattern = r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$"
emails = [
"user@example.com",
"test.user+tag@gmail.com",
"student@school.edu.tw",
"userexample.com",
"user@",
"@example.com",
"user@example",
"user@example.c"
]
for email in emails:
if re.fullmatch(email_pattern, email):
print(email, "格式正確")
else:
print(email, "格式錯誤")
```
也可以直接使用 `fullmatch()`,因此不一定要在表達式中加入 `^` 和 `$`:
```python
email_pattern = r"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}"
email = "user@example.com"
if re.fullmatch(email_pattern, email):
print("Email 格式正確")
else:
print("Email 格式錯誤")
```
---
# 5. 使用 `re.compile()` 重複比對
如果同一個正規表達式會使用多次,可以先編譯:
```python
import re
phone_regex = re.compile(r"09\d{8}")
email_regex = re.compile(
r"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}"
)
phone = "0912345678"
email = "user@example.com"
if phone_regex.fullmatch(phone):
print("手機號碼正確")
if email_regex.fullmatch(email):
print("Email 格式正確")
```
---
## 注意事項
正規表達式通常只能檢查「格式」,不能保證資料真的有效。
例如:
- `0912345678` 符合手機號碼格式,但不代表這個號碼真的存在。
- `user@example.com` 符合 Email 基本格式,但不代表該信箱可以收信。
- Email 的完整規格非常複雜,上述寫法是一般表單驗證常用的簡化版本。
實務上,若要驗證整個輸入值,通常優先使用:
```python
re.fullmatch(...)
```
而不是只使用 `re.search()`,因為 `search()` 只要字串中有一部分符合即可。
相關學習地圖、教學課程
Python 資料工程
Python 後端工程、資料庫