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

PHP 保證單詞完整性的 UTF-8 英文字串截取函數實作

     編輯:PHP 綜合知識

直接使用 substr 截取 UTF-8 英文混合字串時,常會切斷多位元組字元導致亂碼。本文提供一個 usubstr 函數,透過前後各檢查 6 個位元組的 UTF-8 編碼規則,智慧補全被切斷的字元,確保截取結果不含殘缺字元,並自動附加省略號。

完整函數程式碼

/**
 * 完整單詞的 UTF-8 字串截取
 *
 * @param string $str      待截取字串
 * @param int    $start    起始位置 (支援負數)
 * @param int|null $length 截取長度,null 表示截取到結尾
 * @return string 截取後的字串,超出原長度時自動加 '...'
 */
public static function usubstr($str, $start, $length = null) {
    // 1. 先正常截取一次
    $res = substr($str, $start, $length);
    $strlen = strlen($str);

    // 2. 計算前後各 6 位元組區段,用於檢測 UTF-8 邊界
    if ($start >= 0) {
        // 正數 start:向後取 6 字節 (next),向前取 6 字節 (prev)
        $next_start = $start + $length;
        $next_len   = ($next_start + 6 <= $strlen) ? 6 : $strlen - $next_start;
        $next_segm  = substr($str, $next_start, $next_len);

        $prev_start = ($start - 6 > 0) ? $start - 6 : 0;
        $prev_segm  = substr($str, $prev_start, $start - $prev_start);
    } else {
        // 負數 start:轉換為正數索引後同樣處理
        $next_start = $strlen + $start + $length;
        $next_len   = ($next_start + 6 <= $strlen) ? 6 : $strlen - $next_start;
        $next_segm  = substr($str, $next_start, $next_len);

        $start      = $strlen + $start;
        $prev_start = ($start - 6 > 0) ? $start - 6 : 0;
        $prev_segm  = substr($str, $prev_start, $start - $prev_start);
    }

    // 3. 檢查後方 6 字節是否以不完整 UTF-8 開頭,若是則補全
    if (preg_match('@^([\x80-\xBF]{0,5})[\xC0-\xFD]?@', $next_segm, $bytes)) {
        if (!empty($bytes[1])) {
            $res .= $bytes[1];
        }
    }

    // 4. 檢查前方 6 字節是否以不完整 UTF-8 結尾,若是則前綴補全
    $ord0 = ord($res[0]);
    if (128 <= $ord0 && 191 >= $ord0) { // 首字節為延續字節 (10xxxxxx)
        if (preg_match('@[\xC0-\xFD][\x80-\xBF]{0,5}$@', $prev_segm, $bytes)) {
            if (!empty($bytes[0])) {
                $res = $bytes[0] . $res;
            }
        }
    }

    // 5. 若結果短於原字串,加上省略號
    if (strlen($res) < $strlen) {
        $res .= '...';
    }

    return $res;
}

核心邏輯解析

UTF-8 編碼規則速查

字節數首字節範圍延續字節範圍
1 (ASCII)0x00-0x7F-
20xC0-0xDF0x80-0xBF
30xE0-0xEF0x80-0xBF
40xF0-0xF70x80-0xBF

判斷邏輯

  1. 向後檢查:截取位置後 6 字節若以延續字節 (0x80-0xBF) 開頭,說明截斷處於多位元組字元中間,需將這些延續字節補到結果尾部。
  2. 向前檢查:結果首字節若為延續字節,說明截取起始處於字元中間,需從前 6 字節中找到該字元的首字節 (0xC0-0xFD) 並補到結果頭部。
  3. 6 字節緩衝區:UTF-8 最長 4 字節,6 字節足以覆蓋任意邊界情況。

使用範例

$str = "Hello 世界 PHP 編程";
// 從位置 6 開始截取 10 個位元組
echo usubstr($str, 6, 10); 
// 輸出: "世界 PHP..." (不會出現亂碼或半個中文字)

適用場景與限制

  • ✅ 適用:UTF-8 編碼、混合中英、需保證字元完整的摘要生成
  • ❌ 不適用:GBK/Big5 等非 UTF-8 編碼、純 ASCII 高效能場景 (直接用 substr 即可)
  • ⚠️ 注意:函數按位元組計算長度,非字元數;若需按字元數截取,請改用 mb_substr 配合 mb_internal_encoding('UTF-8')

現代替代方案 (PHP 7.2+)

// 內建多位元組安全截取,按字元數計算
$str = "Hello 世界 PHP 編程";
echo mb_substr($str, 6, 10, 'UTF-8'); // 輸出: "世界 PHP 編"
echo mb_strimwidth($str, 6, 20, '...', 'UTF-8'); // 含省略號

若專案環境支援 mbstring 擴展,優先使用內建函數;否則本 usubstr 是無擴展依賴的優秀備選。

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