正則匹配是文字處理的瑞士軍刀。本文以「模式 → 解析 → 實戰」三層結構,系統講解基礎錨點、字元類別、量詞、分組、修飾符的組合邏輯,並給出 Email、URL、HTML 標籤、日誌、CSV、日期等高頻場景的生產級模式與 PHP 代碼範例。
| 元素 | 語法 | 作用 |
|---|---|---|
| 錨點 | ^ $ \A \Z \z \b \B | 定位位置,不消耗字元 |
| 字元類別 | [abc] [a-z] [^abc] [:alpha:] \p{Han} \d \w \s | 匹配字元集合 |
| 量詞 | * + ? {m,n} *? +? ?? {m,n}? *+ ++ ?+ {m,n}+ | 控制重複次數與模式 |
| 分組 | (...) (?:...) (?<name>...) (?=...) (?<=...) (?>...) | 捕獲、非捕獲、命名、斷言、原子 |
| 或運算 | a|b|c | 任一匹配,優先級最低 |
| 修飾符 | i m s x u U D J | 改變引擎行為 |
filter_var($email, FILTER_VALIDATE_EMAIL))// 驗證
/^[^@\s]+@[^@\s]+\.[^@\s]+$/isu
// 結構化提取
/^(?<local>[^@\s]+)@(?<domain>(?<sub>[\w-]+\.)*(?<tld>[\w-]+))$/isu
// 完整 URL 驗證
/^https?:\/\/(?:[\p{L}\p{N}-]+\.)+[\p{L}]{2,}(?:\/[\p{L}\p{N}._~!$&'()*+,;=:@%/-]*)?$/u
// 解析協議、域名、路徑、查詢、片段
/^(?<scheme>https?):\/\/(?<host>[\p{L}\p{N}-]+(?:\.[\p{L}\p{N}-]+)*)(?:\/(?<path>[\p{L}\p{N}._~!$&'()*+,;=:@%/-]*))?(?:\?(?<query>[\p{L}\p{N}._~!$&'()*+,;=:@%/-]*))?(?:#(?<fragment>[\p{L}\p{N}._~!$&'()*+,;=:@%/-]*))?$/u
// 單標籤屬性 key="value"
/(\w+)\s*=\s*"([^"]*)"/
// 圖片 src 提取
/<img\s+[^>]*src\s*=\s*["']([^"']+)["']/i
// 連結 href + 錨文本
/<a\s+[^>]*href\s*=\s*["']([^"']+)["'][^>]*>(.*?)<\/a>/is
// ISO 8601 Y-m-d H:i:s
/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/
// 常見中文日期 2023年12月1日 / 2023-12-01 / 2023/12/01
/^\d{4}[年\/\-](0?[1-9]|1[0-2])[月\/\-](0?[1-9]|[12]\d|3[01])[日]?$/
// 時間戳 (10/13 位)
/^\d{10}(\d{3})?$/
// IPv4
/^((25[0-5]|2[0-4]\d|[01]?\d?\d)\.){3}(25[0-5]|2[0-4]\d|[01]?\d?\d)$/
// CIDR 192.168.1.0/24
/^((25[0-5]|2[0-4]\d|[01]?\d?\d)\.){3}(25[0-5]|2[0-4]\d|[01]?\d?\d)\/(3[0-2]|[12]?\d)$/
/^(?<ip>\S+)\s+(?<ident>\S+)\s+(?<user>\S+)\s+\[(?<time>[^\]]+)\]\s+"(?<request>[^"]+)"\s+(?<status>\d{3})\s+(?<size>\d+)\s+"(?<referer>[^"]*)"\s+"(?<ua>[^"]*)"$/
// 解析出:ip, ident, user, time, request, status, size, referer, ua
// 單行 CSV
$fields = preg_split('/,(?=(?:[^"]*"[^"]*")*[^"]*$)/', $line);
// 多行 CSV 需用狀態機或 str_getcsv()
$fields = str_getcsv($line); // PHP 內建,正確處理所有邊界
/^1[3-9]\d{9}$/
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[~!@#$%^&*]).{8,20}$/
preg_split('/([。!?;])/u', $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
function isValidEmail(string $email): bool {
return (bool)preg_match('/^[^@\s]+@[^@\s]+\.[^@\s]+$/isu', $email);
}
function parseDate(string $date): ?array {
if (preg_match('/^(?<y>\d{4})-(?<m>\d{2})-(?<d>\d{2})$/', $date, $m)) {
return ['year'=>(int)$m['y'], 'month'=>(int)$m['m'], 'day'=>(int)$m['d']];
}
return null;
}
function extractLinks(string $html): array {
preg_match_all('/<a\s+href="([^"]+)"[^>]*>(.*?)<\/a>/is', $html, $m, PREG_SET_ORDER);
return array_map(fn($match) => ['url'=>$match[1], 'text'=>strip_tags($match[2])], $m);
}
function highlightKeywords(string $text, array $keywords): string {
if (empty($keywords)) return $text;
$pattern = '/' . implode('|', array_map('preg_quote', $keywords, ['/'])) . '/iu';
return preg_replace_callback($pattern, fn($m) => '' . $m[0] . '', $text);
}
ereg('abc', $s) → preg_match('/abc/', $s)eregi('abc', $s) → preg_match('/abc/i', $s)s:/./sereg_replace('a.*b', '-', $s) → preg_replace('/a.*?b/', '-', $s) (非貪婪) 或 /a[^b]++b/ (佔有優先)ereg('(a)(b)', $s, $r) → preg_match('/(a)(b)/', $s, $r),$r[1] 同義。strpos、str_replace、explode、str_getcsv。^pattern$ 避免掃描整字串。[^"]* 比 .*? 快 10 倍且安全。++ *+ 鎖定結構:零回溯,線性時間。收藏本模式庫,下次遇到文字提取、驗證、清洗、重構任務,直接複製適配,專注業務邏輯開發。