正規表達式完全指南:從基礎到實戰應用

你是否曾在編程論壇上看到一串密密麻麻的符號如 /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,感到既神秘又敬畏?那就是正規表達式(Regular Expression,簡稱 Regex)。儘管它初看起來如同密碼,卻是每一位開發者、資料分析師、內容編輯都應該至少深入理解一次的強大工具。本文將帶你從歷史背景、核心概念、常用模式,一直講到實戰應用,讓你從「看不懂」進階到「能寫能用」。

一、正規表達式簡史與核心概念

正規表達式從何而來?

在 1950 年代,數學家 Stephen Kleene 在形式語言理論的研究中引入了「正規語言」(Regular Language)的概念。到了 1970 年代,Unix 工具 sedgrep 首次將正規表達式應用於實際的文字搜尋與替換,至此,Regex 便成為了 Unix 文化的一部分。如今,無論是 Perl、Python、JavaScript、PHP、Java 還是 C++,幾乎所有主流程式語言都內建或支援正規表達式,成為了跨領域的通用技能。

什麼是正規表達式?

簡單來說,正規表達式是一種用符號定義文字模式的方式。它不是一門語言本身,而是一種模式描述法。給定一段文本和一個正規表達式,引擎會告訴你:「這段文本中哪些部分符合這個模式?」或「用這個模式替換成那個模式」。

例如,如果你想找出一篇文章中所有「單獨成行的數字」(例如年份、編號),用正規表達式就能簡潔地表達——比起寫一堆 if-else 和 for 迴圈,Regex 通常是更優雅的選擇。

二、基礎語法:逐個符號的深度講解

字符集與量詞

正規表達式的核心是字符集量詞的組合。以下是最常用的幾種:

字符集

  • .:匹配任意單個字符(除了換行符,某些引擎可設定包含換行)
  • [abc]:字符類,匹配 a、b 或 c 中的任一個
  • [a-z]:範圍,匹配小寫字母 a 到 z
  • [^abc]:否定字符類,匹配除了 a、b、c 之外的任何字符
  • \d:匹配任意數字(等同 [0-9]
  • \D:匹配非數字字符
  • \w:匹配單字字符(字母、數字、底線,等同 [a-zA-Z0-9_]
  • \W:匹配非單字字符
  • \s:匹配任意空白字符(空格、制表符、換行符)
  • \S:匹配非空白字符

量詞

  • *:0 個或多個(貪心量詞)
  • +:1 個或多個(貪心量詞)
  • ?:0 個或 1 個(可選)
  • {n}:恰好 n 個
  • {n,}:至少 n 個
  • {n,m}:至少 n 個,至多 m 個
  • *?+???:非貪心版本(懶惰量詞)

錨點

  • ^:行起始位置
  • $:行結束位置
  • \b:單詞邊界(字符與非字符之間的位置)
  • \B:非單詞邊界

逃脫特殊字符

某些符號在 Regex 中有特殊含義(如 .*+?[]() 等)。若想匹配字面上的這些符號,需要在前面加上反斜線 \ 進行逃脫。例如,要匹配句號 . 的字面意義,應寫成 \.

三、常用模式實例:從簡到繁

電郵地址驗證

一個簡化但實用的電郵正規表達式:

^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$

解讀:

  • ^$:確保模式從頭匹配到尾
  • [a-zA-Z0-9._%+-]+:帳號部分,一個或多個合法字符
  • @:字面的 @ 符號
  • [a-zA-Z0-9.-]+:域名的主要部分
  • \.:字面的點
  • [a-zA-Z]{2,}$:至少 2 個字母的頂級域名(.com、.tw、.org 等)

電話號碼格式

匹配台灣手機號碼(09xx-xxxx-xxxx 格式):

^09\d{2}-\d{4}-\d{4}$

IP 地址(IPv4)

匹配任意有效的 IPv4 位址:

^(\d{1,3}\.){3}\d{1,3}$

注意:這個簡化版本不會檢查每個八位組是否在 0-255 範圍內,完整版本會更複雜。

日期格式(YYYY-MM-DD)

^\d{4}-\d{2}-\d{2}$

URL 驗證

一個基本的 URL 正規表達式:

^https?://[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}(/.*)?$

四、進階技巧:捕獲與回溯參考

捕獲群組

圓括號不只用來分組,它還定義了捕獲群組,可以在匹配後存取並重複使用。例如:

(\d{4})-(\d{2})-(\d{2})

匹配日期時,會捕獲三個群組:第 1 組是年份、第 2 組是月份、第 3 組是日期。在替換操作中,可以用 $1$2$3 引用這些群組。

非捕獲群組

有時你只想分組但不需要捕獲,可以使用 (?:...) 語法:

(?:cat|dog) ate

這會匹配 "cat ate" 或 "dog ate",但不會占用捕獲槽位。

向前查看與向後查看

有時需要匹配「前面或後面是某某」的位置,而不消耗那些字符。例如,匹配「後面跟著 'ing'」的單詞:

\w+(?=ing)

或者匹配「前面是 'price: '」的數字:

(?<=price: )\d+

五、常見誤區與性能陷阱

貪心量詞 vs 懶惰量詞

預設情況下,量詞如 *+ 是「貪心」的,它們會匹配盡可能多的字符。考慮以下例子:

const regex = /<.*>/;
const text = '<div>content</div>';

預期是匹配 <div>,但貪心的 .* 實際上會匹配 <div>content</div>——整個字串!若要修正,改用懶惰量詞 .*? 即可。

特殊字符忘記逃脫

許多初學者在撰寫 Regex 時忘記逃脫句號、括號等特殊字符,導致模式不符預期。記住:若要匹配字面的特殊字符,務必加上 \

效能災難:重複的量詞與回溯

某些欠佳設計的正規表達式會導致「災難性回溯」(Catastrophic Backtracking),使得引擎花費指數級時間去嘗試各種匹配組合。例如:

(a+)+b

若輸入是一長串 'a' 但沒有 'b',引擎會在每一步都嘗試回溯,導致性能劇降。避免這類模式的秘訣是:盡量限制量詞的範圍,使用非貪心量詞,或者明確加上邊界條件。

六、實務應用範例

驗證電話號碼

在 Web 表單中驗證使用者輸入的電話號碼:

function validatePhone(phoneNumber) {
    const regex = /^09\d{2}-\d{4}-\d{4}$/;
    return regex.test(phoneNumber);
}

console.log(validatePhone("0912-3456-7890")); // true
console.log(validatePhone("12345")); // false

從文本中提取電子郵件

const text = "聯繫我:[email protected][email protected]";
const emailRegex = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g;
const emails = text.match(emailRegex);
console.log(emails); // ["[email protected]", "[email protected]"]

替換與格式化

將日期格式從 YYYY-MM-DD 改為 DD/MM/YYYY:

const date = "2026-03-18";
const reformatted = date.replace(/(\d{4})-(\d{2})-(\d{2})/, "$3/$2/$1");
console.log(reformatted); // "18/03/2026"

去除 HTML 標籤

雖然用 Regex 去除 HTML 標籤不是最佳實踐(應該用 HTML 解析器),但簡單示例如下:

const html = "<p>這是一段 <strong>重要</strong> 文字。</p>";
const plainText = html.replace(/<[^>]+>/g, "");
console.log(plainText); // "這是一段 重要 文字。"

七、工具與線上資源

掌握 Regex 最好的方式就是不斷練習。使用正規表達式產生器工具可以實時測試你的模式,看看它如何匹配各種輸入。同時,也推薦查閱以下資源:

  • MDN Web Docs:JavaScript RegExp 的詳細文件
  • Regex101.com:線上 Regex 測試工具,支援多種語言與風格
  • RegexPal:另一個優秀的線上測試平台
  • Regex Cheat Sheet:快速速查表

此外,不同的程式語言和工具可能在 Regex 實現上有細微差異。例如,Java 和 JavaScript 的量詞語法相同,但 Perl 支援一些更高級的特性。在實際應用中,熟悉你所用語言的 Regex 方言很重要。

八、總結與進階方向

正規表達式是一項初看複雜、但一旦掌握就能大幅提升開發效率的技能。核心要點是:

  • 理解字符集、量詞、錨點的組合邏輯
  • 透過實際例子(電郵、電話、日期等)建立直覺
  • 留意性能陷阱,特別是貪心量詞與回溯問題
  • 在實務中頻繁測試與迭代,不要過度最佳化

若要進一步深化,可探索 PCRE(Perl Compatible Regular Expressions)、命名捕獲群組、更複雜的向前/向後查看,甚至撰寫自己的 Regex 引擎以理解其內部運作。但對大多數日常編程任務而言,本文涵蓋的內容已足敷應用。

現在,打開正規表達式產生器工具,試著編寫幾個模式來匹配你自己的數據集吧。實踐是最好的老師。