正則表達式中 捕獲組 與 非捕獲組 是進階模式匹配的核心概念。本文系統整理四種捕獲組語法、反向引用、命名捕獲、非捕獲組、零寬斷言 (預查) 等關鍵知識點,並附完整 PHP 驗證範例。
一、捕獲組類型
| 語法 | 名稱 | 說明 |
(pattern) | 普通捕獲組 | 匹配並編號儲存 (從 1 起),可巢狀,$matches[1] 存取 |
(?<name>pattern) | 命名捕獲組 | 指定名稱,$matches['name'] 直接存取,編號也保留 |
\n / \k<name> | 反向引用 | 模式內引用前面捕獲組內容 (\1、\2... 或 \k<name>) |
(?:pattern) | 非捕獲組 | 僅分組不儲存,不佔用編號,提升效能 |
二、程式碼驗證範例
// 1. 普通捕獲組與巢狀
$regex = '/(ab(c)+)+d(e)?/';
$str = 'abccde';
preg_match($regex, $str, $m);
print_r($m);
/* 輸出:
[0] => abccde // 整體匹配
[1] => abcc // 第1組 (外層)
[2] => c // 第2組 (內層 c)
[3] => e // 第3組 (e)
*/
// 2. 命名捕獲組
$regex = '/(?<g1>\w(?<g2>\w))abc(?<g3>\w)45/';
$str = 'fsabcd45';
preg_match($regex, $str, $m);
print_r($m);
/* 輸出:
[0] => fsabcd45
[g1] => fs
[1] => fs
[g2] => s
[2] => s
[g3] => d
[3] => d
*/
// 3. 反向引用 \1 \2 (注意單引號!)
$regex = '/(\w)(\w)\2\1/'; // 匹配 abba, baab 等回文結構
$str = 'abba';
preg_match($regex, $str, $m); // $m[1]='a', $m[2]='b'
// 4. 命名反向引用 \k<name>
$regex = '/(?<name>\w)abc\k<name>/';
$str = 'fabcf';
preg_match_all($regex, $str, $m);
// $m['name'][0] = 'f'
三、非捕獲組與零寬斷言 (預查)
| 語法 | 類型 | 含義 |
(?=pattern) | 正向肯定預查 | 後面必須匹配 pattern,不消耗字元 |
(?!pattern) | 正向否定預查 | 後面不能匹配 pattern |
(?<=pattern) | 反向肯定預查 | 前面必須匹配 pattern |
(?<!pattern) | 反向否定預查 | 前面不能匹消 pattern |
// 只匹配被 a 包圍的 bc
$regex = '/(?<=a)bc(?=d)/';
$str = 'abcd ebcd abce ebca';
preg_match_all($regex, $str, $m);
// $m[0] = ['bc'] (只有第一個 abcd 中的 bc 符合)
// 零寬度特性示範
// /HE(?=L)LLO/ 匹配 HELLO (共5字元)
// /HE(?=L)LO/ 不匹配 HELLO (模式只有4字元,預查不佔寬度)
四、實戰技巧
- 效能:不需捕獲內容時優先用
(?:...),減少記憶體分配與陣列建構。
- 可讀性:複雜正則善用命名捕獲
(?<name>...),配合 \k<name> 反向引用,代碼自文檔化。
- 調試:使用
preg_match_all() 觀察 $matches 結構,確認組編號與命名對應關係。
- 單引號字串:PHP 正則模式字串**強烈建議用單引號**,避免雙引號轉義干擾 (如
\1 在雙引號中會被解析)。