2025年6月10日 星期二

PHP中兩個字串 $str1 = 'yabadabadoo' 和 $str2 = 'yaba',如何檢查 $str1 是否包含 $str2?請注意 strpos 的潛在陷阱並修正。

 要檢查一個字串 $str1 是否包含另一個字串 $str2,我們可以使用 PHP 內建的 strpos() 函數。然而,strpos() 存在一個常見的「陷阱」:如果子字串 $str2$str1開頭(也就是索引 0)被找到,strpos() 會返回 0。在布林上下文中,0 會被評估為 false,這可能導致判斷錯誤。


strpos() 的潛在陷阱與修正

讓我們看看這個潛在的陷阱:

PHP
<?php
$str1 = 'yabadabadoo';
$str2 = 'yaba';

// 錯誤的檢查方式:
if (strpos($str1, $str2) == FALSE) { // 或者 !strpos($str1, $str2)
    echo "'$str1' 不包含 '$str2' (錯誤判斷)\n";
} else {
    echo "'$str1' 包含 '$str2'\n";
}

// 修正後的檢查方式:
if (strpos($str1, $str2) !== FALSE) {
    echo "'$str1' 包含 '$str2' (正確判斷)\n";
} else {
    echo "'$str1' 不包含 '$str2'\n";
}
?>

在上面的例子中,strpos($str1, $str2) 會返回 0,因為 'yaba' 就在 'yabadabadoo' 的開頭。

  • 當我們使用 == FALSE 進行比較時,0 == FALSEtrue,導致程式誤判為不包含。
  • 正確的修正方法是使用嚴格比較運算符 !== FALSE(或 === 0 進行精確匹配,但 !== FALSE 更通用於任何位置的查找),這樣就能區分子字串不存在(返回 false)和子字串在開頭(返回 0)。

完整的程式碼範例

以下是如何正確檢查 $str1 是否包含 $str2 的程式碼:

PHP
<?php

function containsString(string $haystack, string $needle): bool
{
    /**
     * 檢查一個字串是否包含另一個字串。
     *
     * @param string $haystack 搜尋的原始字串。
     * @param string $needle   要搜尋的子字串。
     * @return bool            如果包含則返回 true,否則返回 false。
     */
    // 使用 !== FALSE 進行嚴格比較,避免 strpos 返回 0 時的誤判
    return strpos($haystack, $needle) !== FALSE;
}

// 範例 1: 子字串在開頭
$str1_a = 'yabadabadoo';
$str2_a = 'yaba';
if (containsString($str1_a, $str2_a)) {
    echo "案例 1: '$str1_a' 包含 '$str2_a'\n"; // 預期輸出:包含
} else {
    echo "案例 1: '$str1_a' 不包含 '$str2_a'\n";
}

// 範例 2: 子字串在中間
$str1_b = 'hello world';
$str2_b = 'world';
if (containsString($str1_b, $str2_b)) {
    echo "案例 2: '$str1_b' 包含 '$str2_b'\n"; // 預期輸出:包含
} else {
    echo "案例 2: '$str1_b' 不包含 '$str2_b'\n";
}

// 範例 3: 子字串不存在
$str1_c = 'programming';
$str2_c = 'code';
if (containsString($str1_c, $str2_c)) {
    echo "案例 3: '$str1_c' 包含 '$str2_c'\n";
} else {
    echo "案例 3: '$str1_c' 不包含 '$str2_c'\n"; // 預期輸出:不包含
}

// 範例 4: 空字串作為子字串
$str1_d = 'abc';
$str2_d = '';
if (containsString($str1_d, $str2_d)) {
    echo "案例 4: '$str1_d' 包含 '$str2_d' (空字串通常被認為是包含的)\n"; // 預期輸出:包含
} else {
    echo "案例 4: '$str1_d' 不包含 '$str2_d'\n";
}

?>

其他考慮

除了 strpos(),PHP 還提供了其他函數來檢查字串包含性,例如:

  • strstr(): 這個函數會在 $haystack 中查找 $needle,如果找到,則返回 $needle 及其之後的部分;如果找不到,則返回 FALSE。它的行為與 strpos() 類似,也需要使用嚴格比較 (!== FALSE)。
  • str_contains() (PHP 8+ 引入): 這是 PHP 8 及更高版本中引入的一個專門用於檢查字串包含性的函數。它直接返回布林值 truefalse,因此沒有 strpos() 的陷阱,使用起來更直觀、安全。如果您的環境允許,強烈建議使用此函數

使用 str_contains() 的範例:

PHP
<?php
// 僅適用於 PHP 8 及更高版本

$str1 = 'yabadabadoo';
$str2 = 'yaba';

if (str_contains($str1, $str2)) {
    echo "使用 str_contains(): '$str1' 包含 '$str2'\n";
} else {
    echo "使用 str_contains(): '$str1' 不包含 '$str2'\n";
}
?>

總之,當使用 strpos() 時,務必記住使用嚴格比較運算符 !== FALSE 來避免因子字串在索引 0 導致的判斷錯誤。如果您的 PHP 版本是 8 或更高,那麼 str_contains() 則是更簡潔、更安全的選擇。

沒有留言:

張貼留言

網誌存檔