preg_match_all 是 PHP 批次匹配正則表達式的核心函數,能一次性提取所有符合模式的子串並保留捕獲組。本文以「解析多個 DIV 區塊的 ID 與內容」為主線,逐步拆解正則構建思路、陣列結構、常見陷阱與最佳實踐。
$html = '<div id="biuuu">php100</div><div id="biuuu_2">php1002</div><div id="biuuu_3">php1003</div>';
需提取:biuuu、biuuu_2、biuuu_3 與對應內容 php100、php1002、php1003。
<div id="([^"]+)">([^<]+)</div>([^"]+):捕獲組 1,匹配非雙引號字元 (ID)([^<]+):捕獲組 2,匹配非 < 字元 (內容),避免貪婪吞噬後續標籤/<div id="([^"]+)">([^<]+)<\/div>/<?php
$html = '<div id="biuuu">php100</div><div id="biuuu_2">php1002</div><div id="biuuu_3">php1003</div>';
$pattern = '/<div id="([^"]+)">([^<]+)<\/div>/';
preg_match_all($pattern, $html, $matches, PREG_SET_ORDER);
echo "完整匹配陣列結構 (PREG_SET_ORDER):\n";
print_r($matches);
/* 輸出:
Array
(
[0] => Array
(
[0] => <div id="biuuu">php100</div> // 整段匹配
[1] => biuuu // 捕獲組 1
[2] => php100 // 捕獲組 2
)
[1] => Array
(
[0] => <div id="biuuu_2">php1002</div>
[1] => biuuu_2
[2] => php1002
)
[2] => Array
(
[0] => <div id="biuuu_3">php1003</div>
[1] => biuuu_3
[2] => php1003
)
)
*/
// 業務處理
foreach ($matches as $m) {
echo "ID: {$m[1]}, Content: {$m[2]}\n";
}
| 旗標 | 陣列結構 | 適用場景 |
|---|---|---|
PREG_SET_ORDER (推薦) |
$matches[0] = [全匹配, 組1, 組2...] |
逐筆處理,語義清晰 |
PREG_PATTERN_ORDER (預設) |
$matches[0] = [全匹配陣列], $matches[1] = [組1陣列]... |
需分別操作各捕獲組陣列時 |
| 陷阱 | 原因 | 對策 |
|---|---|---|
| 貪婪匹配吞噬多個標籤 | .* 或 .+ 匹配盡可能多字元 | 使用非貪婪 .*? 或排除字元類 [^<]+ |
| 跨行匹配失效 | 點號 . 預設不匹配換行 | 加 s 修飾符 /pattern/s 或用 [\s\S]*? |
| 特殊字元未轉義 | /、.、*、?、(、) 等 | 使用 preg_quote() 或手動加反斜線 |
| 編碼不一致 | 字串為 UTF-8 但模式無 u 修飾符 | 加 u 修飾符 /pattern/u,確保字元邊界正確 |
| 災難性回溯 | 巢狀量詞 (a+)+ 遇長字串 | 避免巢狀量詞,改用確定性模式或具體字元類 |
$html = '<div class="box" id="A">...</div><div id="B" class="box">...</div>';
// 使用前瞻/後瞻或多模式
$pattern = '/<div\b(?=[^>]*\bid="([^"]+)")[^>]*>([^<]+)<\/div>/';
// 解釋:(?=...) 正向前瞻確保 id 存在並捕獲,不消耗字元
DOMDocument + DOMXPath 解析 HTML/XML,正則僅用於非結構化文本或極簡片段。u 修飾符支援 Unicode。PREG_SET_ORDER 並配合 foreach 處理。正則表達式是雙刃劍:威力強大但易寫成「寫時讀不懂」的代碼。掌握 preg_match_all 陣列結構、貪婪/非貪婪、修飾符、常見陷阱,並建立「能用 DOM 解析就不用正則」的原則,才能在資料提取任務中游刃有餘。