在字符串解析、日誌分析、數據清洗中,提取數字是高頻操作。本文系統梳理 PHP 正則提取數字的三大核心模式、常見業務場景解決方案、性能優化與避坑指南。
| 模式 | 正則 | 匹配行為 | 適用場景 |
|---|---|---|---|
| 連續數字組 | /\d+/ | 貪婪匹配連續數字,202px → 202 | 提取所有數值(坐標、尺寸、ID) |
| 單個數字 | /\d/ | 逐個匹配,202 → 2,0,2 | 統計數字出現次數、校驗碼計算 |
| 固定長度 | /\d{8}/ | 精確匹配 8 位數字 | 身份證年份、電話號碼段、日期 |
| 長度範圍 | /\d{4,8}/ | 匹配 4-8 位連續數字 | 不定長業務編碼 |
| 帶邊界約束 | /\b\d{11}\b/ | 單詞邊界,避免匹配長數字片段 | 手機號、銀行卡號提取 |
<?php
$css = "left:0px; top:202px; width:90px; height:30px; opacity:0.5; z-index:999";
preg_match_all('/\d+(\.\d+)?/', $css, $matches);
// 結果: [0, 202, 90, 30, 0.5, 999] (浮點數需 \.\d+)
print_r($matches[0]);
?>
<?php
function extract_code($str, $len = 8) {
// 使用前瞻/後顧斷言確保前後非數字,避免截取長數字片段
$pattern = '/(?
場景三:提取所有數字並轉換為整型數組
<?php
function extract_all_ints($str) {
preg_match_all('/\d+/', $str, $m);
return array_map('intval', $m[0] ?? []);
}
$str = "用戶ID: 10086, 積分: 999, 等級: VIP5";
print_r(extract_all_ints($str)); // [10086, 999, 5]
?>
場景四:複雜文本中提取手機號(中國大陸)
<?php
function extract_mobile($text) {
// 11位,以1開頭,第二位3-9,後9位任意數字,邊界約束
$pattern = '/(?
性能優化與最佳實踐
1. 預編譯正則(靜態變量緩存)
<?php
function match_pattern($str, $pattern) {
static $compiled = [];
if (!isset($compiled[$pattern])) {
$compiled[$pattern] = $pattern; // PHP 內部自動緩存編譯結果
}
return preg_match($compiled[$pattern], $str);
}
?>
2. 避免災難性回溯
.*、.+ 貪婪量詞,改用具體字符類 [^"]*。/^prefix\d+/ 比 /\d+/ 快數量級。preg_match_all 替代循環 preg_match。<?php
// 大文件流式處理,避免一次性讀入內存
$handle = fopen('huge.log', 'r');
while (($line = fgets($handle)) !== false) {
if (preg_match('/\d{10,}/', $line, $m)) {
process($m[0]);
}
}
fclose($handle);
?>
| 錯誤代碼 | 問題 | 修正 |
|---|---|---|
/\d{4}(\.\d+)?/ |
小數點未轉義,匹配 2024a05 |
/\d{4}(\.\d+)?/ → /\d{4}(\.\d+)?/ (點在字符類外需轉義 \.) |
preg_match('/\d+/', $str, $m); echo $m[1]; |
索引錯誤:$m[0] 是完整匹配,$m[1] 是第一個捕獲組 |
無捕獲組時直接用 $m[0];有捕獲組 (\d+) 才用 $m[1] |
/\d+/u 處理中文數字 |
\d 僅匹配 ASCII 0-9,不匹配 123(全形) |
用 /[0-90-9]+/u 或 /\p{Nd}+/u (Unicode 數字屬性) |
PHP 正則提取數字核心在於選對量詞(+/*/{n,m})、加邊界約束(\b/(?。業務代碼中建議封裝為 NumberExtractor 工具類,內置常用場景預設模式,統一異常處理與單元測試,避免正則碎片散落各處難以維護。