正則表達式是文本處理利器,PHP 推薦使用 PCRE (Perl 兼容) 函數族。本文聚焦 preg_match(單次匹配)與 preg_match_all(全局匹配)的區別、參數詳解、常見陷阱及中文匹配技巧。
PCRE 正則需包裹在定界符中(常用 /.../),結尾可加修飾符:
i:忽略大小寫s:. 匹配換行符m:多行模式(^$ 匹配行首尾)u:UTF-8 模式(處理中文必加)U:非貪婪模式<?php
// 語法:int preg_match(string $pattern, string $subject, array &$matches = null)
if (preg_match('/php/i', 'PHP is the web scripting language.', $matches)) {
echo "匹配到: " . $matches[0]; // 輸出: PHP
} else {
echo "未匹配";
}
// $matches[0] = 整個模式匹配內容
// $matches[1] = 第一個捕獲組,以此類推
?>
特點:首次匹配成功即返回 1 並停止,效率高,適合「判斷是否包含」或「提取第一處」。
<?php
$url = 'https://www.jb51.net/index.html';
preg_match('/^(https?:\/\/)?([^\/]+)/i', $url, $m);
$host = $m[2]; // www.jb51.net
preg_match('/[^\.\/]+\.[^\.\/]+$/', $host, $m);
echo "域名: {$m[0]}"; // jb51.net
?>
<?php
// 語法:int preg_match_all(string $pattern, string $subject, array &$matches, int $flags = 0)
// flags 常用值:
// PREG_PATTERN_ORDER (默認):$matches[0] = 所有完整匹配,$matches[1] = 第一個捕獲組所有匹配...
// PREG_SET_ORDER:$matches[0] = 第一次匹配的所有捕獲組,$matches[1] = 第二次...
// PREG_OFFSET_CAPTURE:同時返回偏移量
$str = '<pre>學習php很快樂。</pre><pre>所有phper需努力!</pre>';
$kw = 'php';
preg_match_all('/<pre>([\s\S]*?)<\/pre>/', $str, $mat);
for ($i = 0; $i < count($mat[0]); $i++) {
$content = $mat[1][$i];
$content = str_replace($kw, '<span style="color:red">' . $kw . '</span>', $content);
$str = str_replace($mat[1][$i], $content, $str);
}
echo $str; // 所有 內的 php 變紅
?>
| 特性 | preg_match | preg_match_all |
|---|---|---|
| 匹配次數 | 最多 1 次 | 全文掃描,所有匹配 |
| 返回值 | 0/1 (false/true) | 匹配總次數 (int),出錯 false |
| $matches 結構 | [0]=全匹配, [1]=第1組... | 受 $flags 控制,默認按組分組 |
| 典型用途 | 驗證格式、提取首個、判斷包含 | 批量提取、統計次數、全文替換 |
| 性能 | 極快(早停) | 需掃描全文,稍慢 |
/[\x80-\xff]+/ 或 /[\xa1-\xff]+//[\x{4e00}-\x{9fa5}]+/u (必加 u 修飾符)<?php
$str = '學習php是一件快樂的事。';
// UTF-8 環境
preg_match_all('/[\x{4e00}-\x{9fa5}]+/u', $str, $match);
print_r($match[0]);
/*
Array
(
[0] => 學習
[1] => 是一件快樂的事
)
*/
?>
strpos、str_replace、explode 效率高得多。.* 會吞盡後面內容,用 .*? 或 U 修飾符。(?:...) 非捕獲組不佔編號。. 按字節匹配,導致中文亂碼或錯誤截斷。\ 需雙重轉義,建議用單引號定義正則。