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

正則表達式實戰:字符串查找與模式匹配完全指南

     編輯:PHP 相關知識

核心需求

在字符串中查找另一個字符串,支援:任意位置、開頭匹配、結尾匹配、大小寫敏感/不敏感。這是文本處理、日誌分析、輸入驗證的基礎操作。

PHP 字符串查找函數對比

函數類型大小寫返回值效能適用場景
strpos()原生敏感位置/false最快簡單子串查找、高頻調用
stripos()原生不敏感位置/false極快不區分大小寫查找
str_contains()原生 (PHP 8+)敏感bool最快僅需判斷是否存在
preg_match()正則可選1/0/false較慢複雜模式、邊界條件、提取捕獲組
mb_strpos()多字節敏感位置/false中等UTF-8 多語言文本

正則模式設計:位置錨點與修飾符

<?php
function regexSearch(string $haystack, string $needle, string $position = 'any', bool $caseSensitive = false): bool {
    // 1. 轉義特殊字符(將 needle 視為字面字符串)
    $pattern = preg_quote($needle, '/');
    
    // 2. 根據位置添加錨點
    switch ($position) {
        case 'start':  // 開頭匹配
            $pattern = '^' . $pattern;
            break;
        case 'end':    // 結尾匹配
            $pattern = $pattern . '$';
            break;
        case 'any':    // 任意位置(預設)
        default:
            // 無錨點
            break;
    }
    
    // 3. 修飾符
    $modifiers = $caseSensitive ? '' : 'i';  // i: 不區分大小寫
    // 可選:s 讓 . 匹配換行,m 多行模式 ^$ 匹配行首尾
    $modifiers .= 'u';  // u: UTF-8 模式(推薦)
    
    // 4. 執行匹配
    return (bool)preg_match('/' . $pattern . '/' . $modifiers, $haystack);
}

// 使用範例
$text = "Hello World\nHello PHP\nHELLO REGEX";

var_dump(regexSearch($text, 'World'));           // true (任意位置,不區分大小寫)
var_dump(regexSearch($text, 'World', 'any', true)); // false (區分大小寫)
var_dump(regexSearch($text, 'Hello', 'start'));     // true (開頭)
var_dump(regexSearch($text, 'PHP', 'start'));       // false (非開頭)
var_dump(regexSearch($text, 'REGEX', 'end'));       // true (結尾)
var_dump(regexSearch($text, 'hello', 'any', false)); // true (不區分大小寫)
?>

進階模式:詞邊界、全詞匹配

<?php
function wholeWordSearch(string $haystack, string $word, bool $caseSensitive = false): bool {
    // \b 詞邊界:字母數字下劃線與非字母數字下劃線的交界
    $pattern = '\b' . preg_quote($word, '/') . '\b';
    $modifiers = ($caseSensitive ? '' : 'i') . 'u';
    return (bool)preg_match('/' . $pattern . '/' . $modifiers, $haystack);
}

$text = "cat, catalog, concatenate, wildcat";
var_dump(wholeWordSearch($text, 'cat'));      // true (獨立單詞 cat)
var_dump(wholeWordSearch($text, 'catalog'));  // true
var_dump(wholeWordSearch($text, 'cat', true)); // false (大小寫敏感下無 match)
?>

正則替代方案:原生函數組合

<?php
function nativeSearch(string $haystack, string $needle, string $position = 'any', bool $caseSensitive = false): bool {
    $haystackCmp = $caseSensitive ? $haystack : mb_strtolower($haystack, 'UTF-8');
    $needleCmp = $caseSensitive ? $needle : mb_strtolower($needle, 'UTF-8');
    
    switch ($position) {
        case 'start':
            return str_starts_with($haystackCmp, $needleCmp);  // PHP 8+
        case 'end':
            return str_ends_with($haystackCmp, $needleCmp);    // PHP 8+
        case 'any':
        default:
            return str_contains($haystackCmp, $needleCmp);     // PHP 8+
    }
}

// PHP 7 兼容寫法
function str_starts_with_compat(string $haystack, string $needle): bool {
    return $needle === '' || strncmp($haystack, $needle, strlen($needle)) === 0;
}
function str_ends_with_compat(string $haystack, string $needle): bool {
    return $needle === '' || strcmp(substr($haystack, -strlen($needle)), $needle) === 0;
}
function str_contains_compat(string $haystack, string $needle): bool {
    return $needle !== '' && strpos($haystack, $needle) !== false;
}
?>

效能基準測試

<?php
$haystack = str_repeat("The quick brown fox jumps over the lazy dog. ", 10000); // ~430KB
$needle = "lazy dog";
$iterations = 1000;

$tests = [
    'strpos (區分大小寫)' => fn() => strpos($haystack, $needle) !== false,
    'stripos (不區分)' => fn() => stripos($haystack, $needle) !== false,
    'str_contains (PHP 8+)' => fn() => str_contains($haystack, $needle),
    'preg_match (不區分, u修飾符)' => fn() => preg_match('/' . preg_quote($needle, '/') . '/iu', $haystack),
    'mb_stripos' => fn() => mb_stripos($haystack, $needle, 0, 'UTF-8') !== false,
];

foreach ($tests as $name => $fn) {
    $start = microtime(true);
    for ($i = 0; $i < $iterations; $i++) { $fn(); }
    echo "$name: " . (microtime(true) - $start) . "s\n";
}

// 典型輸出 (PHP 8.2, 430KB 字符串, 1000 次):
// strpos (區分大小寫): 0.008s
// stripos (不區分): 0.012s
// str_contains (PHP 8+): 0.008s
// preg_match (不區分, u修飾符): 0.095s
// mb_stripos: 0.045s
?>

選擇指南

  1. 簡單子串判斷存在性:str_contains() (PHP 8+) / strpos() !== false — 首選,最快
  2. 需獲取位置/提取上下文:strpos()/stripos()/mb_strpos()
  3. 開頭/結尾匹配:str_starts_with()/str_ends_with() (PHP 8+) / strncmp()/substr()
  4. 全詞匹配/詞邊界:正則 /\bword\b/iu
  5. 複雜模式(通配符、量詞、選項、捕獲組):正則 preg_match()
  6. 多字節/Unicode 文本:優先 mb_* 或正則 /u 修飾符

常見陷阱

  1. ❌ strpos() === false 判斷不存在 → ✅ !== false(0 也是 false)
  2. ❌ 直接用用戶輸入作正則 → ✅ preg_quote($input, '/') 轉義
  3. ❌ 正則未加 u 處理中文 → ✅ 所有中文正則必加 u 修飾符
  4. ❌ 大量循環中重複編譯正則 → ✅ 將模式預編譯或用原生函數
  5. ❌ preg_match() 返回 0 視為錯誤 → ✅ 僅 false 為錯誤,0 為不匹配

字符串查找看似簡單,選對工具能帶來數量級效能差異。原生函數處理 90%+ 場景,正則專注於「原生無法表達」的複雜模式。記住:能用 str_contains 就別用 preg_match。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved