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

PHP 多位元組安全截取函數:z_substr 解決中文亂碼問題

     編輯:PHP 相關知識

背景

PHP 內建 substr 按位元組截取,對 UTF-8 中文 (3 位元組/字) 會造成截半個字元產生亂碼。mb_substr 雖支援多位元組,但早期版本需安裝 mbstring 擴充套件且效能較差。本文提供一個不依賴擴充套件、純 PHP 實作的中英混排安全截取函數 z_substr。

函數完整程式碼

[php]
/**
 * 多位元組安全截取函數,防止中文亂碼
 *
 * @param string $sourcestr 來源字串
 * @param int    $i         起始位元組索引 (預設 0)
 * @param int    $cutlength 截取長度 (以「字元寬度」計:中文=1, 英文=0.5)
 * @param string $endstr    超過長度時的尾端字串 (預設空)
 * @return string 截取後字串
 */
function z_substr($sourcestr = '', $i = 0, $cutlength = 150, $endstr = '')
{
    $str_length = strlen($sourcestr); // 總位元組數
    $returnstr  = '';
    $n = 0; // 已截取的「字元寬度」計數

    while ($n < $cutlength && $i <= $str_length) {
        $temp_str = substr($sourcestr, $i, 1); // 取 1 位元組
        $ascnum   = ord($temp_str);            // 取 ASCII 值

        if ($ascnum >= 224) {
            // UTF-8 三位元組字元 (中文、日文等):1110xxxx 10xxxxxx 10xxxxxx
            $returnstr .= substr($sourcestr, $i, 3);
            $i += 3;
            $n++; // 中文算 1 寬度
        } elseif ($ascnum >= 192) {
            // UTF-8 二位元組字元 (歐文擴展):110xxxxx 10xxxxxx
            $returnstr .= substr($sourcestr, $i, 2);
            $i += 2;
            $n++; // 算 1 寬度
        } else {
            // ASCII 單位元組字元 (英文、數字、符號)
            $returnstr .= substr($sourcestr, $i, 1);
            $i += 1;
            $n += 0.5; // 英文算 0.5 寬度 (兩個英文寬度約等一個中文)
        }
    }

    // 若未截完整串,加上尾端字串 (如 "...")
    if ($i < $str_length) {
        $returnstr .= $endstr;
    }

    return $returnstr;
}

原理解析

UTF-8 位元組模式首位元組範圍ord() 值範圍處理方式
1 位元組 (ASCII)0xxxxxxx0 - 127直接取 1 位元組,寬度 +0.5
2 位元組110xxxxx192 - 223取 2 位元組,寬度 +1
3 位元組 (中文)1110xxxx224 - 239取 3 位元組,寬度 +1
4 位元組 (Emoji 等)11110xxx240 - 247本函數未處理,會誤判

函數透過檢查首位元組 ord() 值判斷字元佔用位元組數,按完整字元單位複製,避免截半字元。

使用範例

[php]
$str = "PHP中文截取測試abcdefg";

// 截取寬度 10 (約 5 個中文或 10 個英文)
echo z_substr($str, 0, 10, '...');
// 輸出:PHP中文截取...

// 從位元組索引 6 開始 (跳過 "PHP中文" 9 位元組)
echo z_substr($str, 9, 8, '..');
// 輸出:截取測試ab..

優缺點與現代替代方案

優點

  • 零依賴,不需 mbstring、iconv 擴充套件。
  • 邏輯簡單,效能尚可 (單純位元組操作)。
  • 可自訂「中英寬度比例」 (預設中:英 = 1:0.5),適合版面對齊需求。

缺點

  • 不支援 4 位元組 UTF-8 字元 (Emoji、生僻字),會誤判為 3 位元組或單獨位元組。
  • 手動計算寬度而非真實字元數,精確度視字型而定。
  • PHP 5.4+ 環境建議直接用 mb_substr($str, 0, 10, 'UTF-8'),原生、標準、支援完整 Unicode。

現代最佳實踐建議

[php]
// PHP 5.4+ / PHP 7/8 推薦寫法
function safe_substr($string, $start, $length, $encoding = 'UTF-8') {
    if (extension_loaded('mbstring')) {
        return mb_substr($string, $start, $length, $encoding);
    }
    // 降級相容:無 mbstring 時使用 z_substr 邏輯
    return z_substr($string, $start, $length);
}

若專案仍在 PHP 5.2/5.3 且無法安裝擴充套件,z_substr 是不錯的備選方案;否則請優先使用 mb_substr。

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