正則表達式需配合處理函數才能發揮作用。PHP 基於 PCRE 庫提供 preg_* 系列函數,性能優於 POSIX 正則。本文系統講解四大核心函數:匹配、全局匹配、替換、分割,含參數詳解、常見陷阱、實戰示例。
int preg_match(string $pattern, string $subject, array &$matches = null, int $flags = 0, int $offset = 0)
$matches[0] 為完整匹配,[1]... 為捕獲組。PREG_OFFSET_CAPTURE 旗標可獲取匹配位置。<?php
$pattern = '/<b>(.*?)<\/b>/';
$str = '<b>welcome</b> <b>to</b> php';
if (preg_match($pattern, $str, $m)) {
echo "首次匹配: {$m[0]}\n"; // welcome
echo "捕獲組1: {$m[1]}\n"; // welcome
}
?>
int preg_match_all(string $pattern, string $subject, array &$matches = null, int $flags = PREG_PATTERN_ORDER, int $offset = 0)
PREG_PATTERN_ORDER:$matches[0] 所有完整匹配,$matches[1] 所有第1組捕獲...PREG_SET_ORDER:$matches[0] = 第一次匹配的所有組,結構更直觀。<?php
preg_match_all($pattern, $str, $m, PREG_SET_ORDER);
print_r($m);
/* 輸出:
Array
(
[0] => Array ( [0]=> welcome [1]=> welcome )
[1] => Array ( [0]=> to [1]=> to )
)
*/
?>
mixed preg_replace(mixed $pattern, mixed $replacement, mixed $subject, int $limit = -1, int &$count = null)
$pattern $replacement $subject 均可為陣列,支援批量。$limit 限制每個模式替換次數,-1 無限制。$count 返回實際替換總次數。$replacement 中用 $1 ${2} 引用捕獲組(不要用 \1,僅模式中用)。preg_replace_callback()。<?php
// 1. 簡單替換
echo preg_replace('/\d+/', '*', 'Age: 25, Year: 2024'); // Age: *, Year: *
// 2. 回調函數處理(替代 /e)
$str = 'php mysql';
echo preg_replace('/(php)|(mysql)/', fn($m) => strtoupper($m[0]), $str); // PHP MYSQL
// 3. 陣列批量
$patterns = ['/a/', '/b/'];
$replacements = ['A', 'B'];
echo preg_replace($patterns, $replacements, 'abc'); // ABc
// 4. 限制次數
echo preg_replace('/\s+/', '-', 'a b c', 1); // a-b c (只替換第一處)
?>
array preg_split(string $pattern, string $subject, int $limit = -1, int $flags = 0)
$limit > 0:最多返回 $limit 個元素,最後一個包含剩餘內容。$limit < 0:返回除最後 abs($limit) 個元素外的所有。PREG_SPLIT_NO_EMPTY:忽略空結果。PREG_SPLIT_DELIM_CAPTURE:將捕獲組也包含在結果中。PREG_SPLIT_OFFSET_CAPTURE:返回 [匹配內容, 偏移位置]。<?php
$str = '標題:PHP 正則;內容:preg 函數講解。';
// 1. 按中文標點分割,保留標點
print_r(preg_split('/([,。;:])/u', $str, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY));
/* 輸出:
[標題, :, PHP 正則, ;, 內容, :, preg 函數講解, 。]
*/
// 2. 限制分割數
print_r(preg_split('/\s+/', 'a b c d', 2)); // [0]=>a [1]=>b c d
// 3. 獲取偏移
print_r(preg_split('/\b/', 'ab cd', -1, PREG_SPLIT_OFFSET_CAPTURE | PREG_SPLIT_NO_EMPTY));
/* 每個元素: [匹配文本, 在原字符串中的字節偏移] */
?>
| 陷阱 | 正確做法 |
|---|---|
| 用 \1 引用捕獲組在 replacement 中 | 用 $1 或 ${1} |
| 模式中未轉義分隔符(如 /path/to/file/) | 用其他分隔符 #pattern# 或 ~pattern~ |
| 貪婪匹配導致過度吞噬 | 用懶惰量詞 *? +? ?? 或具體字符類 [^>]* |
| 大量數據用 preg_replace 替代 str_replace | 無正則需求時,str_replace 快 10 倍+ |
| 忽略 u 修飾符處理 UTF-8 中文 | 模式末尾加 u:/漢字/u |
preg_match:判斷是否匹配、提取首次結果。preg_match_all:提取所有匹配、解析結構化文本。preg_replace:模式替換、格式化、清洗數據。preg_split:複雜分割、保留分隔符、詞法分析。strpos, explode, str_replace)解決的,絕不寫正則。