核心正則語法速查
| 元字符 | 含義 | 示例 |
. | 任意字符 (除換行) | a.c 匹配 abc, axc |
* | 前字符 0~n 次 (貪婪) | ab*c 匹配 ac, abc, abbc |
+ | 前字符 1~n 次 | ab+c 匹配 abc, abbc |
? | 前字符 0~1 次 | ab?c 匹配 ac, abc |
.*? | 非貪婪匹配 (最少) | <div>.*?</div> 匹配單層 |
(...) | 捕獲組 (可反向引用 $1) | (\d{4})-(\d{2}) |
(?:...) | 非捕獲組 (僅分組) | (?:http|https):// |
[] | 字符類 | [a-zA-Z] |
\d \w \s | 數字/單詞字符/空白 | |
實戰 1:提取圖片 URL (支援單雙引號、屬性順序不固定)
<?php
$html = '<p><img src="img1.jpg" alt="圖1"><img alt="圖2" src=\'img2.png\' class="thumb"></p>';
// 正則解析:
//
]* 非 > 字符 (屬性區)
// src= src 屬性
// (["']) 捕獲引號類型 (組1)
// (.*?) 非貪婪捕獲 URL (組2) - 核心目標
// \1 反向引用相同引號閉合
// [^>]* 其餘屬性
// > 標簽結束
$pattern = '/
]*src=(["\'])(.*?)\1[^>]*>/i';
preg_match_all($pattern, $html, $matches, PREG_SET_ORDER);
$images = [];
foreach ($matches as $m) {
$images[] = [
'quote' => $m[1], // 引號類型
'url' => $m[2], // 圖片地址
'full' => $m[0] // 完整標簽
];
}
print_r($images);
/*
Array
(
[0] => Array ( [quote] => " [url] => img1.jpg [full] =>
)
[1] => Array ( [quote] => ' [url] => img2.png [full] =>
)
)
*/
實戰 2:提取超鏈接與鏈接文本
<?php
$html = '<a href="https://example.com" class="link">示例網站</a>
<a id="top" href=\'https://test.org\' target="_blank">測試站點</a>';
// 正則: ]* href=(["']) (.*?) \1 [^>]* > (.*?)
$pattern = '/]*href=(["\'])(.*?)\1[^>]*>(.*?)<\/a>/is';
preg_match_all($pattern, $html, $matches, PREG_SET_ORDER);
$links = [];
foreach ($matches as $m) {
$links[] = [
'url' => $m[2], // href 值
'text' => trim(strip_tags($m[3])), // 鏈接文本 (去除可能嵌套標簽)
'full' => $m[0]
];
}
print_r($links);
/*
Array
(
[0] => Array ( [url] => https://example.com [text] => 示例網站 ... )
[1] => Array ( [url] => https://test.org [text] => 測試站點 ... )
)
*/
實戰 3:提取頁面標題 <title>
<?php
$html = '網頁標題 - 站點名稱';
$pattern = '/]*>(.*?)<\/title>/is';
if (preg_match($pattern, $html, $m)) {
echo "標題: " . trim($m[1]); // 網頁標題 - 站點名稱
}
實戰 4:提取 meta 標簽信息 (SEO 關鍵)
<?php
$html = '<meta name="description" content="頁面描述內容">
<meta property="og:title" content="分享標題">';
$pattern = '/]*(?:name|property)=(["\'])(.*?)\1[^>]*content=\1(.*?)\1/';
preg_match_all($pattern, $html, $matches, PREG_SET_ORDER);
foreach ($matches as $m) {
echo "{$m[2]}: {$m[3]}\n";
}
// description: 頁面描述內容
// og:title: 分享標題
進階技巧:DOMDocument 替代正則 (強烈推薦)
正則解析 HTML 的局限: HTML 結構複雜 (屬性換行、註釋、CDATA、非標準閉合),正則極難覆蓋所有邊界情況。PHP 內建 DOMDocument 是專業解析器,健壯性遠超正則。
<?php
$html = '<div class="content"><img src="a.jpg"><a href="link.html">文本</a></div>';
$dom = new DOMDocument();
// 抑制非標準 HTML 產生的警告
libxml_use_internal_errors(true);
$dom->loadHTML('' . $html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
libxml_clear_errors();
// 1. 提取所有圖片
$images = [];
foreach ($dom->getElementsByTagName('img') as $img) {
$images[] = $img->getAttribute('src');
}
// 2. 提取所有鏈接
$links = [];
foreach ($dom->getElementsByTagName('a') as $a) {
$links[] = [
'url' => $a->getAttribute('href'),
'text' => trim($a->textContent)
];
}
// 3. 提取標題
$title = $dom->getElementsByTagName('title')->item(0)?->textContent ?? '';
// 4. XPath 精準查詢 (如: 類為 thumb 的圖片)
$xpath = new DOMXPath($dom);
$thumbImages = $xpath->query('//img[contains(@class, "thumb")]');
foreach ($thumbImages as $img) { /* ... */ }
print_r(compact('images', 'links', 'title'));
常見陷阱與優化
| 問題 | 解決 |
| 貪婪匹配導致跨標簽捕獲 | 使用非貪婪 .*? 或具體字符類 [^"']* |
| 跨行匹配失敗 | 加 s 修飾符 (DOTALL) 讓 . 匹配換行 |
| 大小寫敏感 | 加 i 修飾符 |
| 特殊字符轉義 | 在字符類 [] 中 - ] ^ \ 需轉義或放首尾 |
| 性能災難 (回溯) | 避免嵌套量詞 (a*)*,用具體字符類替代 .* |
總結建議
- 簡單提取 (已知結構固定): 正則表達式編寫快、執行快,適用
preg_match_all。
- 複雜/不規範 HTML 解析: **強制使用 DOMDocument + DOMXPath**,容錯率高、語義清晰、可維護。
- 大規模採集: 考慮
symfony/dom-crawler 或 sunra/php-simple-html-dom-parser 等成熟庫,支援 CSS 選擇器語法 ($crawler->filter('img.thumb')->attr('src'))。
- 編碼處理:
loadHTML 前加 防止中文亂碼。