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

PHP 多位元組字串截取:支援 UTF-8 與 GB2312 的 mb_substr 替代方案

     編輯:PHP 相關知識

在 PHP 早期版本或未安裝 mbstring 擴展的環境下,處理中文等多位元組編碼的字串截取是常見痛點。本文提供兩個相容 UTF-8 與 GB2312/Big5 的自訂函數,並說明核心邏輯與現代替代方案。

函數一:ssubstr() - 通用多位元組截取(支援 UTF-8 / GB2312)

<?php
function ssubstr($string, $length, $dot = ' ...') {
    global $charset; // 慣例由全域變數指定編碼:'utf-8'、'gb2312'、'big5'
    if (strlen($string) <= $length) return $string;

    // 預處理 HTML 實體
    $string = str_replace(['&', '"', '<', '>'], ['&', '"', '<', '>'], $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
                $tn = 1; $n++; $noc++;
            } elseif (194 <= $t && $t <= 223) { // 2 bytes
                $tn = 2; $n += 2; $noc += 2;
            } elseif (224 <= $t && $t <= 239) { // 3 bytes
                $tn = 3; $n += 3; $noc += 2;
            } elseif (240 <= $t && $t <= 247) { // 4 bytes
                $tn = 4; $n += 4; $noc += 2;
            } elseif (248 <= $t && $t <= 251) { // 5 bytes
                $tn = 5; $n += 5; $noc += 2;
            } elseif ($t == 252 || $t == 253) { // 6 bytes
                $tn = 6; $n += 6; $noc += 2;
            } else {
                $n++;
            }
            if ($noc >= $length) break;
        }
        if ($noc > $length) $n -= $tn;
        $strcut = substr($string, 0, $n);
    } else {
        // GB2312 / Big5:雙位元組編碼,高位元組 > 127
        for ($i = 0; $i < $length; $i++) {
            $strcut .= ord($string[$i]) > 127 ? $string[$i] . $string[++$i] : $string[$i];
        }
    }
    // 還原 HTML 實體
    $strcut = str_replace(['&', '"', '<', '>'], ['&', '"', '<', '>'], $strcut);
    return $strcut . $dot;
}
?>

函數二:wordscut() - 簡易版(僅 GB2312/Big5)

<?php
function wordscut($string, $length, $suffix = true) {
    if (strlen($string) <= $length) return $string;
    if ($suffix) { $length -= 3; $addstr = '...'; } else { $addstr = ''; }
    $wordscut = '';
    for ($i = 0; $i < $length; $i++) {
        if (ord($string[$i]) > 127) {
            $wordscut .= $string[$i] . $string[$i + 1];
            $i++;
        } else {
            $wordcut .= $string[$i];
        }
    }
    return $wordscut . $addstr;
}
?>

核心原理解析

編碼判斷依據中文字元位元組數
UTF-8首位元組範圍:
194-223(2B) 224-239(3B) 240-247(4B)...
通常 3 位元組
GB2312/Big5首位元組 > 127(高位元組)固定 2 位元組

現代最佳實務:優先使用 mbstring

PHP 5.2+ 內建 mbstring 擴展(多數主機預設開啟),強烈建議直接使用:

<?php
// 確保腳本編碼與內部編碼一致
mb_internal_encoding('UTF-8');

$str = "這是一段測試字串,包含英文 abc 123。";
echo mb_substr($str, 0, 10, 'UTF-8') . '...'; // 這是一段測試字...
?>

輔助函數:多位元組字串長度計算

<?php
function mstrlen($str, $charset = 'UTF-8') {
    if (function_exists('mb_strlen')) return mb_strlen($str, $charset);
    if (function_exists('iconv_strlen')) return iconv_strlen($str, $charset);
    // 相容 fallback:正則計算 UTF-8 字元數
    preg_match_all('/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|\xe0[\xa0-\xbf][\x80-\xbf]|[\xe1-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3}/', $str, $ar);
    return count($ar[0]);
}
?>

使用建議

  1. 新專案:直接用 mb_substr()、mb_strlen(),設定 mb_internal_encoding('UTF-8')。
  2. 舊環境維護:引入上述 ssubstr(),並確保 $charset 全域變數正確設定。
  3. 資料庫層面:MySQL LEFT()、SUBSTRING() 在多位元組編碼下同樣會按位元組截斷,建議應用層處理。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved