在字符串中查找另一個字符串,支援:任意位置、開頭匹配、結尾匹配、大小寫敏感/不敏感。這是文本處理、日誌分析、輸入驗證的基礎操作。
| 函數 | 類型 | 大小寫 | 返回值 | 效能 | 適用場景 |
|---|---|---|---|---|---|
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
?>
str_contains() (PHP 8+) / strpos() !== false — 首選,最快strpos()/stripos()/mb_strpos()str_starts_with()/str_ends_with() (PHP 8+) / strncmp()/substr()/\bword\b/iupreg_match()mb_* 或正則 /u 修飾符strpos() === false 判斷不存在 → ✅ !== false(0 也是 false)preg_quote($input, '/') 轉義u 處理中文 → ✅ 所有中文正則必加 u 修飾符preg_match() 返回 0 視為錯誤 → ✅ 僅 false 為錯誤,0 為不匹配字符串查找看似簡單,選對工具能帶來數量級效能差異。原生函數處理 90%+ 場景,正則專注於「原生無法表達」的複雜模式。記住:能用 str_contains 就別用 preg_match。