正則引擎簡介
PHP 採用 PCRE(Perl Compatible Regular Expressions) 函式庫,支援 Perl 風格語法,功能強大且效能優異。所有 PCRE 函數均以 preg_ 為前綴。
核心語法要素
1. 定界符
- 成對出現,如
/pattern/、#pattern#、~pattern~。
- 可使用任意非英數字元、非反斜線字元。
2. 原子
最小匹配單位:字母、數字、中文字、逸出字元(\.、\[ 等)。
3. 元字元與量詞
| 符號 | 含義 |
\ | 逸出字元 |
^ | 字串開頭(多行模式 m 時為行首) |
$ | 字串結尾(多行模式 m 時為行尾) |
. | 任意單一字元(預設不含換行,s 修飾符可含換行) |
* | 前面原子 0 次或多次(貪婪) |
+ | 前面原子 1 次或多次(貪婪) |
? | 前面原子 0 次或 1 次(貪婪) |
{n} | 精確 n 次 |
{n,} | 至少 n 次 |
{n,m} | n 到 m 次 |
4. 字元類別
| 符號 | 等價 | 說明 |
\d | [0-9] | 數字 |
\D | [^0-9] | 非數字 |
\s | [\f\n\r\t\v] | 空白字元 |
\S | [^\f\n\r\t\v] | 非空白 |
\w | [0-9a-zA-Z_] | 單字字元(含底線) |
\W | [^0-9a-zA-Z_] | 非單字字元 |
\b | | 單字邊界 |
\B | | 非單字邊界 |
5. 分組與斷言
| 語法 | 名稱 | 說明 |
(pattern) | 捕獲群組 | 匹配並編號捕獲,可用 \1、$1 反向引用 |
(?:pattern) | 非捕獲群組 | 僅分組,不佔用捕獲編號 |
(?=pattern) | 正向肯定預查 | 匹配後面是 pattern 的位置,不消耗字元 |
(?!pattern) | 正向否定預查 | 匹配後面不是 pattern 的位置 |
(?<=pattern) | 反向肯定預查 | 匹配前面是 pattern 的位置 |
(?<!pattern) | 反向否定預查 | 匹配前面不是 pattern 的位置 |
6. 模式修飾符
| 修飾符 | 效果 |
i | 不區分大小寫 |
m | 多行模式:^/$ 匹配行首尾 |
s | 單行模式:. 匹配含換行 |
x | 忽略模式中的空白與註釋 |
U | 反轉貪婪:.* 變非貪婪,.*? 變貪婪 |
A | 強制從字串開頭匹配(同 ^) |
D | $ 僅匹配字串絕對結尾,忽略結尾換行 |
核心 PCRE 函數速查
| 函數 | 用途 |
preg_match() | 單次匹配,回傳 0/1,可選擇性填入 matches 陣列 |
preg_match_all() | 全域匹配,回傳匹配次數,matches 為多維陣列 |
preg_replace() | 搜尋替換,支援回調函數、陣列批次替換 |
preg_replace_callback() | 替換時使用回調函數動態產生替換字串 |
preg_split() | 依正則分割字串為陣列 |
preg_grep() | 篩選陣列中匹配模式的元素 |
preg_filter() | 類似 preg_replace 但僅回傳有變化的元素 |
preg_quote() | 將字串中的正則特殊字元逸出 |
preg_last_error() | 取得上次 PCRE 執行的錯誤代碼 |
實用範例
<?php
// 1. 驗證 Email(簡易版)
$email = 'user@example.com';
var_dump(preg_match('/^[\w.-]+@[\w.-]+\.[a-z]{2,}$/i', $email)); // 1
// 2. 提取所有連結
$html = '<a href="https://a.com">A</a> <a href=\'https://b.org\'>B</a>';
preg_match_all('/href=["\']([^"\']+)["\']/', $html, $m);
print_r($m[1]); // Array([0]=>https://a.com, [1]=>https://b.org)
// 3. 非貪婪匹配 HTML 標籤內容
$str = '<div>Hello</div><div>World</div>';
preg_match_all('/<div>(.*?)<\/div>/s', $str, $m);
print_r($m[1]); // Array([0]=>Hello, [1]=>World)
// 4. 替換多個空白為單一空格
echo preg_replace('/\s+/', ' ', "Hello \t\n World"); // Hello World
效能與避坑指南
- 避免災難性回溯:慎用巢狀量詞(如
(a+)+),改用佔有優先量詞 ++、*+ 或原子群組 (?>...)。
- 善用定界符選擇:匹配 URL 時用
~ 或 # 避免斜線逸出。
- 大量資料用
preg_match_all 而非迴圈 preg_match。
- 預編譯模式:同一模式重複使用時,考慮靜態變數快取或改用
preg_jit_stack(PHP 7+ JIT)。