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

PHP 中文截取函數:完美兼容 UTF-8 與 GB2312 編碼的 substr_zh 實現

     編輯:PHP 相關知識

痛點分析

PHP 內置 substr 按字節截取,直接用於中文會導致亂碼(UTF-8 一個漢字 3 字節,GB2312 2 字節)。mb_substr 雖支持多字節,但早期版本需安裝 mbstring 擴展。本文提供一個無擴展依賴、雙編碼兼容的純 PHP 實現 substr_zh。

函數簽名

function substr_zh($string, $sublen, $start = 0, $code = 'UTF-8')
  • $string:待截取字符串
  • $sublen:截取長度(字符數)
  • $start:起始位置(字符索引)
  • $code:編碼類型,'UTF-8' 或 'GB2312'(默認 UTF-8)
  • 返回值:截取後字符串,超長時自動添加 ...

核心代碼

<?php
function substr_zh($string, $sublen, $start = 0, $code = 'UTF-8') {
    if ($code == 'UTF-8') {
        // 正則匹配所有合法 UTF-8 字符(含 ASCII、多字節)
        $pa = "/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|\xe0[\xa0-\xbf][\x80-\xbf]|[\xe1-\xef][\x80-\xbf][\x80-\xbf]|\xf0[\x90-\xbf][\x80-\xbf][\x80-\xbf]|[\xf1-\xf7][\x80-\xbf][\x80-\xbf][\x80-\xbf]/";
        preg_match_all($pa, $string, $t_string);
        $chars = $t_string[0];
        if (count($chars) - $start > $sublen) {
            return join('', array_slice($chars, $start, $sublen)) . "...";
        }
        return join('', array_slice($chars, $start, $sublen));
    } else {
        // GB2312/GBK:雙字節字符高位 > 129
        $start *= 2; $sublen *= 2;
        $strlen = strlen($string);
        $tmpstr = '';
        for ($i = 0; $i < $strlen; $i++) {
            if ($i >= $start && $i < ($start + $sublen)) {
                if (ord(substr($string, $i, 1)) > 129) {
                    $tmpstr .= substr($string, $i, 2);
                    $i++;
                } else {
                    $tmpstr .= substr($string, $i, 1);
                }
            }
            // 循環中已處理雙字節跳過,這裡無需額外判斷
        }
        if (strlen($tmpstr) < $strlen) $tmpstr .= "...";
        return $tmpstr;
    }
}

// 測試
$str = "頂置車頂起困境檲上盯協押畏奇才趄肯困楞右腳可愛有";
echo substr_zh($str, 10, 0, 'GB2312'); // 輸出前 10 個漢字
?>

關鍵點解析

UTF-8 正則詳解

正則 $pa 覆蓋了 UTF-8 所有合法字節序列:

  • [\x01-\x7f]:ASCII 字符(1 字節)
  • [\xc2-\xdf][\x80-\xbf]:2 字節字符(基本多文種平面)
  • \xe0[\xa0-\xbf][\x80-\xbf]:3 字節字符(起始碼點較低)
  • [\xe1-\xef][\x80-\xbf][\x80-\xbf]:3 字節字符(常規範圍,含中日韓)
  • \xf0[\x90-\xbf][\x80-\xbf][\x80-\xbf]:4 字節字符(補充平面,Emoji 等)
  • [\xf1-\xf7][\x80-\xbf][\x80-\xbf][\x80-\xbf]:4 字節字符(擴展範圍)

GB2312 邏輯

利用 ord() > 129 判斷高位字節,遇到則取兩字節並索引 $i++ 跳過低位。將字符長度換算為字節長度處理。

現代替代方案

PHP 5.4+ 內置 mb_substr(需 mbstring)已完美解決此問題,且性能更優:

// 推薦現代寫法
echo mb_substr($str, 0, 10, 'UTF-8');

若環境確定有 mbstring,請優先使用內置函數。本函數適用於無法安裝擴展的舊環境或教學參考。

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