preg_match() 和 preg_match_all() 是 PHP 正則表達式提取資料的核心函式。本文透過兩個實戰範例:提取標籤內容、解析 URL 域名,詳細解析正則模式設計、旗標使用、結果陣列結構與常見陷阱。
<?php
$string = '<b>example:</b><div align=left>this is a test</div>';
// 模式:匹配成對標籤及其內容
// <[^>]+> 起始標籤 (非貪婪匹配屬性)
// (.*?) 內容 (非貪婪,捕獲組 1)
// [^>]+> 結束標籤
$pattern = '|<[^>]+>(.*?)</[^>]+>|';
// preg_match_all 找出所有匹配
// PREG_PATTERN_ORDER (預設):$matches[0] 完整匹配,$matches[1] 第一捕獲組...
preg_match_all($pattern, $string, $matches, PREG_PATTERN_ORDER);
print_r($matches);
/* 結果:
Array
(
[0] => Array
(
[0] => <b>example:</b>
[1] => <div align=left>this is a test</div>
)
[1] => Array
(
[0] => example:
[1] => this is a test
)
)
*/
// 輸出提取內容
echo $matches[1][0] . ', ' . $matches[1][1]; // example:, this is a test
?>
<?php
$url = 'https://www.example.com/path/page.html?query=value#anchor';
// 步驟 1:提取 host 部分 (含 port)
if (preg_match('/^(?:https?:\/\/)?([^\/]+)/i', $url, $matches)) {
$host = $matches[1]; // www.example.com
echo "Host: $host\n";
}
// 步驟 2:從 host 提取主域名 (去除 www. 等子域名)
// 匹配:倒數兩段 (example.com) 或 三段 (co.uk 等公共後綴需公共後綴列表)
if (preg_match('/([^\.]+\.[^\.]+)$/', $host, $matches)) {
$domain = $matches[1];
echo "Domain: $domain\n"; // example.com
}
// 一次性正則 (簡易版,不處理公共後綴)
preg_match('/^(?:https?:\/\/)?(?:[^@\/]+@)?([^:\/\n]+)/i', $url, $matches);
$host = $matches[1]; // 含 port
$domain = preg_replace('/^www\./i', '', $host); // 簡易移除 www.
?>
| 模式片段 | 含義 |
|---|---|
|...| | 分隔符 (可用 /, #, ~ 等),避免模式內 / 需轉義 |
<[^>]+> | 匹配起始標籤:< 後接一或多個非 > 字元,再 > |
(.*?) | 非貪婪捕獲任意字元 (含換行需 s 修飾符),捕獲組 1 |
</[^>]+> | 匹配結束標籤 |
^(?:https?:\/\/)? | 行首可選 https:// 或 https:// (非捕獲組) |
([^\/]+) | 捕獲組:一或多個非 / 字元 (host:port) |
([^\.]+\.[^\.]+)$ | 行尾捕獲:兩段非點字元組成的域名 |
<?php
function extractDomain(string $url): ?string {
$parsed = parse_url($url);
if (!$parsed || empty($parsed['host'])) return null;
$host = $parsed['host'];
// 移除 www. 前綴 (簡易)
$host = preg_replace('/^www\./i', '', $host);
// 進階:使用公共後綴列表 (Public Suffix List) 正確提取註冊域名
// 需引入庫如 true/punycode 或 手動維護列表
return $host;
}
$urls = [
'https://www.google.com/search?q=php',
'https://sub.domain.co.uk/path',
'ftp://user:pass@ftp.example.com:21/file.txt',
'//cdn.example.com/js/app.js', // 協議相對 URL
];
foreach ($urls as $url) {
echo "$url => " . extractDomain($url) . PHP_EOL;
}
?>
DOMDocument。.* 導致跨標籤匹配:務必用非貪婪 .*? 或排除字元類別 [^<]*。i (大小寫不敏感)、s (點號匹配換行)、m (多行模式) 常被遺漏。co.uk, com.tw 等需特殊處理,單純正則無法完美解決。preg_match 是強大的字串提取工具,但**正則表達式無法正確解析巢狀結構 (HTML、JSON、XML)**。提取 URL 域名請優先使用 parse_url() 配合公共後綴列表;簡單標籤內容提取可用非貪婪正則,但複雜 HTML 必須改用 DOM 解析器。掌握正則邊界,寫出健壯程式碼。