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

PHP 多位元組字串截取函式:支援 UTF-8/GBK 中文不亂碼的 cutstr 實作

     編輯:PHP 綜合知識

PHP 內建 substr() 僅按位元組截取,對中文等多位元組編碼會造成亂碼。本文提供一個健全的 cutstr() 函式,支援 UTF-8 與 GBK/Big5,正確按「字元寬度」截斷並保留 HTML 實體。

完整函式程式碼

<?php
function cutstr($string, $length, $dot = ' ...') {
    if (strlen($string) <= $length) {
        return $string;
    }

    // 保護 HTML 實體不被截斷
    $pre = chr(1);
    $end = chr(1);
    $string = str_replace(
        ['&', '"', '<', '>'],
        [$pre . '&' . $end, $pre . '"' . $end, $pre . '<' . $end, $pre . '>' . $end],
        $string
    );

    $strcut = '';

    if (strtolower(CHARSET) == 'utf-8') {
        // UTF-8 多位元組邏輯
        $n = $tn = $noc = 0;
        while ($n < strlen($string)) {
            $t = ord($string[$n]);
            if ($t == 9 || $t == 10 || (32 <= $t && $t <= 126)) {
                // ASCII 字元:1 位元組,寬度 1
                $tn = 1; $n++; $noc++;
            } elseif (194 <= $t && $t <= 223) {
                // 2 位元組字元
                $tn = 2; $n += 2; $noc += 2;
            } elseif (224 <= $t && $t <= 239) {
                // 3 位元組字元(中日韓常見)
                $tn = 3; $n += 3; $noc += 2;
            } elseif (240 <= $t && $t <= 247) {
                $tn = 4; $n += 4; $noc += 2;
            } elseif (248 <= $t && $t <= 251) {
                $tn = 5; $n += 5; $noc += 2;
            } elseif ($t == 252 || $t == 253) {
                $tn = 6; $n += 6; $noc += 2;
            } else {
                $n++;
            }
            if ($noc >= $length) break;
        }
        if ($noc > $length) $n -= $tn;
        $strcut = substr($string, 0, $n);
    } else {
        // GBK/Big5:雙位元組判斷
        for ($i = 0; $i < $length; $i++) {
            $strcut .= ord($string[$i]) > 127 ? $string[$i] . $string[++$i] : $string[$i];
        }
    }

    // 還原 HTML 實體
    $strcut = str_replace(
        [$pre . '&' . $end, $pre . '"' . $end, $pre . '<' . $end, $pre . '>' . $end],
        ['&', '"', '<', '>'],
        $strcut
    );

    // 移除截斷處可能殘留的保護標記
    $pos = strrpos($strcut, chr(1));
    if ($pos !== false) $strcut = substr($strcut, 0, $pos);

    return $strcut . $dot;
}
?>

使用範例

// 定義編碼常數(視專案實際編碼設定)
define('CHARSET', 'utf-8');

$text = '這是一段測試中文內容,包含 English & 數字 123。';
echo cutstr($text, 20); 
// 輸出:這是一段測試中文內容,包含 English ...

現代替代方案(PHP 7.2+ 推薦)

若專案使用 PHP 7.2+,建議直接使用 mb_substr() 搭配 mb_strlen(),原生支援多位元組編碼,無需自行實作:

function mb_cutstr($string, $length, $dot = '...', $encoding = 'UTF-8') {
    if (mb_strlen($string, $encoding) <= $length) return $string;
    return mb_substr($string, 0, $length, $encoding) . $dot;
}

若內容含 HTML 標籤,建議搭配 strip_tags() 或使用 mb_substr() 後再配合正則補全標籤,或引用成熟套件如 htmlpurifier。

關鍵設計重點

  1. 編碼偵測: 透過常數 CHARSET 區分 UTF-8 與雙位元組編碼邏輯。
  2. 寬度計算: 中文字元視為寬度 2,ASCII 為 1,符合傳統終端顯示習慣。
  3. HTML 實體保護: 以控制字元 chr(1) 標記實體邊界,避免 &amp; 被截成 &am。
  4. 邊界修正: 超出長度時回退上一個完整字元,避免殘缺位元組。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved