首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP PCRE 正則表達式實戰技巧與效能優化指南

     編輯:PHP 相關知識

PCRE vs POSIX:已塵埃落定

PHP 5.3 棄用、7.0 移除 POSIX 正則 (ereg_* 系列)。全面採用 PCRE (Perl Compatible Regular Expressions),函式前綴 preg_*,語法與 Perl/JavaScript 高度一致,跨語言遷移無縫。

核心語法速查表

元字元說明範例
^字串開頭 (多行模式匹配行首)/^php/i
$字串結尾 (多行模式匹配行尾)/php$/i
\b單詞邊界/\bcat\b/ 匹配 "cat" 不匹配 "category"
\B非單詞邊界/\Bcat\B/ 匹配 "scatter" 中的 "cat"
\d數字 [0-9]/\d{4}-\d{2}-\d{2}/ 日期
\D非數字 [^0-9]
\w字母數字底線 [a-zA-Z0-9_]
\W非字母數字底線
\s空白字元 (空格、Tab、換行、換頁)/\s+/
\S非空白字元
.任意字元 (預設不含換行,s 修飾符含換行)

模式修飾符

實戰技巧精選

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. 前瞻/後顧斷言 - 零寬度斷言

修飾符名稱效果
i忽略大小寫/php/i 匹配 PHP/php/Php
m多行模式^$ 匹配每行首尾
s單行模式 (DOTALL). 匹配含換行的任意字元
x擴展模式忽略模式中空白/註解,利於寫複雜正則
uUTF-8 模式正確處理 Unicode 字元 (中文、Emoji),強烈建議永遠加上
U非貪婪模式反轉量詞貪婪性,*? 變貪婪,* 變非貪婪
eeval (已移除 PHP 7)替換字串作為 PHP 代碼執行,嚴重安全風險,禁用
語法名稱匹配位置
(?=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";
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved