正規表達式以看起來像隨機雜訊而聞名。像 ^[\w.-]+@[\w-]+\.\w{2,}$ 這樣的模式,看上去就像一隻貓在鍵盤上走過。但在晦澀的語法背後,隱藏著一個非常優雅的理念:一種簡潔的語言,用於描述文字中的模式。
無論你是在驗證表單輸入、搜尋日誌檔案、清理資料,還是在程式碼庫中進行尋找替換,正規表達式都是開發者工具箱中最靈活的工具之一。而且你不需要記住每一個晦澀的特性就能從中獲得實際價值。幾個核心構件就能覆蓋絕大多數實際使用場景。
正規表達式到底做什麼
正規表達式(regex 或 regexp)是一個描述一組字串的模式。你將它提供給一個搜尋引擎——可以是程式語言、文字編輯器或命令列工具中的——它就會找到每個匹配的字串。
可以把它理解為升級版的搜尋查詢:
- 一般搜尋: 尋找精確的單字 "error"
- 正規搜尋: 尋找任何看起來像 IP 位址、日期、電子郵件地址或你能描述的任何結構的內容
正規表達式由數學家 Stephen Kleene 於 1956 年發明,並在 1960 年代透過 Unix 文字編輯器進入計算領域。如今,幾乎所有程式語言和文字編輯器都支援正規表達式。
基本構件
字面字元
最簡單的正規表達式就是純文字。模式 hello 會匹配字串中任何出現 "hello" 的地方。就這麼簡單。
點號(.)——任意字元
點號匹配除換行符號以外的任何單一字元。
h.t匹配 "hat"、"hit"、"hot"、"h3t",甚至 "h t"
字元類別([])
方括號定義了某個位置允許出現的字元集合。
[aeiou]— 任何母音字母[0-9]— 任何數字[A-Za-z]— 任何字母[^0-9]— 任何非數字字元(方括號內的^表示「非」)
簡寫類別
| 簡寫 | 含義 | 等價形式 |
|---|---|---|
\d |
任意數字 | [0-9] |
\w |
單字字元 | [A-Za-z0-9_] |
\s |
空白字元 | [ \t\n\r] |
\D |
非數字 | [^0-9] |
\W |
非單字字元 | [^A-Za-z0-9_] |
\S |
非空白字元 | [^ \t\n\r] |
量詞——匹配次數
量詞控制前面的元素必須出現多少次。
| 符號 | 含義 | 範例 | 匹配結果 |
|---|---|---|---|
* |
零次或多次 | ab*c |
"ac"、"abc"、"abbc" |
+ |
一次或多次 | ab+c |
"abc"、"abbc"(不匹配 "ac") |
? |
零次或一次 | colou?r |
"color" 和 "colour" |
{3} |
恰好 3 次 | \d{3} |
"123"、"456" |
{2,4} |
2 到 4 次 | \d{2,4} |
"12"、"123"、"1234" |
錨點——位置
^— 字串開頭(使用m旗標時為行首)$— 字串結尾(或行尾)\b— 單字邊界
模式 ^\d{4}$ 匹配恰好由四個數字組成的字串,如 "2026",但不匹配 "abc2026" 或 "2026xyz"。
分組和選擇
(abc)— 將 "abc" 擷取為一個群組a|b— 匹配 "a" 或 "b"(cat|dog)— 匹配 "cat" 或 "dog"
群組還允許你對序列套用量詞:(ha)+ 匹配 "ha"、"haha"、"hahaha"。
常見實用模式
驗證電子郵件(基礎版)
^[\w.-]+@[\w-]+\.\w{2,}$
它可以匹配 user@example.com、first.last@company.co.uk(部分匹配),並拒絕沒有 @ 或網域的字串。
重要提示: 用正規表達式完美驗證電子郵件地址是出了名的困難——完整的 RFC 5322 規範極其複雜。對於生產系統,建議使用基礎正規表達式進行格式檢查,然後透過寄送確認信來驗證地址。
匹配電話號碼
\+?\d{1,3}[-.\s]?\(?\d{1,4}\)?[-.\s]?\d{3,4}[-.\s]?\d{3,4}
它可以處理 +1 555 123 4567、555-123-4567 和 (555) 123-4567 等格式。
匹配 URL
https?://[\w.-]+(/[\w./?&=-]*)?
匹配 https://example.com、http://example.com/path?q=hello。
匹配日期(YYYY-MM-DD)
\d{4}-\d{2}-\d{2}
匹配 2026-03-29、1999-12-31。注意:這只檢查格式,不檢查有效性——它也會匹配 9999-99-99。
改變行為的旗標
大多數正規表達式引擎支援修改模式套用方式的旗標:
| 旗標 | 名稱 | 效果 |
|---|---|---|
g |
全域 | 尋找所有匹配項,而不僅是第一個 |
i |
不區分大小寫 | hello 匹配 "Hello"、"HELLO" 等 |
m |
多行 | ^ 和 $ 匹配每行的開頭/結尾 |
s |
點號全匹配 | . 也匹配換行符號 |
在 JavaScript 中,旗標附加在結尾斜線之後:/hello/gi。在 Python 中,作為參數傳遞:re.findall(r"hello", text, re.IGNORECASE)。
正規表達式何時是多餘的
正規表達式雖然強大,但並不總是最佳工具:
- 解析 HTML 或 XML。 請使用合適的 DOM 解析器。正規表達式無法可靠地處理巢狀標籤。
- 解析 JSON。 請使用
JSON.parse()或等效方法。正規表達式在邊界情況下會出錯。 - 複雜驗證。 如果你的模式跨越多行且需要五分鐘才能讀懂,考慮改用程序式驗證程式碼。
- 簡單字串操作。 如果你只需要
startsWith()、includes()或split(),一般字串方法更清晰也更快。
常見陷阱
- 忘記跳脫特殊字元。 點號
.匹配任何字元。要匹配字面點號,請使用\.。(、)、[、]、+、*、?、{、}、^、$、|和\同理。 - 貪婪匹配與惰性匹配。 預設情況下,
.*是貪婪的——它會匹配盡可能多的內容。加上?使其變為惰性:.*?匹配盡可能少的內容。在擷取分隔符號之間的內容時,這一點很重要。 - 災難性回溯。 巢狀量詞如
(a+)+在某些輸入上可能導致引擎嘗試指數級數量的路徑,使你的程式凍結。避免在重疊模式上使用巢狀重複。 - 忘記錨點。 沒有
^和$,你的模式會匹配子字串。\d{3}會在 "abc12345" 中匹配 "123"。如果需要精確匹配,請使用^\d{3}$。
進階學習
學習正規表達式最好的方式是實驗。輸入一個模式,貼上一些測試文字,看看哪些內容被標示。不斷調整和迭代,直到你理解每個部分的運作原理。
- 如何測試正規表達式模式 — 包含範例的互動式教學
- 正規表達式測試器 — 貼上你的模式和測試資料,即時查看匹配結果標示
