| 修飾符 | 名稱 | 效果 |
i | 忽略大小寫 | /php/i 匹配 PHP/php/Php |
m | 多行模式 | ^$ 匹配每行首尾 |
s | 單行模式 (DOTALL) | . 匹配含換行的任意字元 |
x | 擴展模式 | 忽略模式中空白/註解,利於寫複雜正則 |
u | UTF-8 模式 | 正確處理 Unicode 字元 (中文、Emoji),強烈建議永遠加上 |
U | 非貪婪模式 | 反轉量詞貪婪性,*? 變貪婪,* 變非貪婪 |
e | eval (已移除 PHP 7) | 替換字串作為 PHP 代碼執行,嚴重安全風險,禁用 |
實戰技巧精選
1. 命名捕獲組 - 可讀性大增
$pattern = '/(?P\d{4})-(?P\d{2})-(?P\d{2})/u';
preg_match($pattern, '2024-05-20', $matches);
// $matches = ['0'=>'2024-05-20', 'year'=>'2024', 'month'=>'05', 'day'=>'20', 1=>'2024', 2=>'05', 3=>'20']
2. 非捕獲組 - 僅分組不佔用反向引用編號
// (?:...) 不計入 $matches 索引
preg_match('/(?:http|https):\/\/([^\/]+)/', $url, $m);
// $m[1] 直接是域名,無需跳過協議組
3. 前瞻/後顧斷言 - 零寬度斷言
| 語法 | 名稱 | 匹配位置 |
(?=pattern) | 正向前瞻 | pattern 之前 |
(?!pattern) | 負向前瞻 | 非 pattern 之前 |
(?<=pattern) | 正向後顧 | pattern 之後 (固定寬度) |
(? | 負向後顧 | 非 pattern 之後 (固定寬度) |
// 提取 action 屬性值,但排除以 http: 開頭
preg_match_all('/action="(?!http:)([^"]+)"/i', $html, $m);
// 替換標籤屬性值,保留引號
$html = preg_replace('/(?<=href=")[^"]+(?=")/', 'https://new.com', $html);
4. 回調函式替換 - 複雜邏輯處理
$url = 'https://example.com';
$html = preg_replace_callback(
'/(?<=action=")(?!http:)([^"]+)(?=")/',
fn($m) => $url . $m[1],
$html
);
5. 避免災難性回溯
- 慎用巢狀量詞:
(a+)+, (a|aa)*
- 固定前綴錨定:
^prefix.*suffix$ 優於 .*prefix.*suffix.*
- 使用具體字元類別替代
.:[^"]* 優於 .*? 匹配引號內容
- 超長字串設定
pcre.backtrack_limit / pcre.recursion_limit (ini_set)
常用驗證正則庫 (已加 u 修飾符)
$regex = [
'email' => '/^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$/u',
'mobile_cn' => '/^1[3-9]\d{9}$/u',
'id_card_cn' => '/^[1-9]\d{5}(19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/u',
'url' => '/^https?:\/\/[^\s\/$.?#].[^\s]*$/iu',
'ipv4' => '/^(?:(?:25[0-5]|2[0-4]\d|[01]?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d?\d)$/u',
'hex_color' => '/^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/u',
];
效能基準測試建議
$pattern = '/your_regex/u';
$subject = str_repeat('test ', 10000);
$start = hrtime(true);
for ($i = 0; $i < 1000; $i++) {
preg_match($pattern, $subject);
}
echo "耗時: " . (hrtime(true) - $start) / 1e6 . " ms\n";
- 上一篇文章: PHP 遞迴掃描目錄查找指定檔案完整實作
- 下一篇文章: PHP 獲取檔案副檔名的三種高效方法與效能對比
Copyright ©
程式碼之家 All Rights Reserved