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

PHP 多編碼安全截取字串函數:支援 UTF-8/GB2312/Big5 精準按字元計數

     編輯:PHP 綜合知識

PHP 內建 substr 按位元組截取,對多位元組編碼 (UTF-8 中文佔 3 位元組、GB2312 佔 2 位元組) 會導致亂碼。mb_substr 雖支援多位元組,但需正確指定編碼。本文提供一個統一介面、自動編碼轉換、支援負索引、邊界保護 的通用截取函數。

核心函數實作

<?php
/**
 * 多編碼安全字串截取
 * 
 * @param string $str       原始字串
 * @param int    $start     起始位置 (0-based,支援負數:-1 為倒數第 1 字元)
 * @param int    $length    截取長度 (預設 -1 表示截取到結尾)
 * @param string $encoding  輸入/輸出編碼 (預設 'UTF-8',支援 'GB2312', 'GBK', 'BIG-5' 等)
 * @param string $suffix    截斷後綴 (預設 '...')
 * @return string 截取後字串
 */
function mb_cut(string $str, int $start = 0, int $length = -1, string $encoding = 'UTF-8', string $suffix = '...'): string {
    // 1. 統一內部處理為 UTF-8
    $internalEnc = 'UTF-8';
    if (strtoupper($encoding) !== $internalEnc) {
        $str = @mb_convert_encoding($str, $internalEnc, $encoding);
        if ($str === false) {
            // 編碼轉換失敗,回傳原字串避免資料損失
            return $str;
        }
    }
    
    // 2. 取得總字元數
    $totalLen = mb_strlen($str, $internalEnc);
    if ($totalLen === 0) return '';
    
    // 3. 處理負數起始索引 (類似 Python/JS slice)
    if ($start < 0) {
        $start = max(0, $totalLen + $start);
    }
    
    // 4. 邊界檢查
    if ($start >= $totalLen) return '';
    
    // 5. 處理長度參數
    if ($length < 0) {
        $length = $totalLen - $start; // 截取到結尾
    } elseif ($length === 0) {
        return '';
    }
    
    // 6. 確保不超出邊界
    $length = min($length, $totalLen - $start);
    
    // 7. 執行截取
    $result = mb_substr($str, $start, $length, $internalEnc);
    
    // 8. 只有真正截斷時才加後綴
    if ($start + $length < $totalLen) {
        $result .= $suffix;
    }
    
    // 9. 轉回原始編碼
    if (strtoupper($encoding) !== $internalEnc) {
        $result = @mb_convert_encoding($result, $encoding, $internalEnc);
    }
    
    return $result;
}

// 別名函數:常見用法簡化
function cut_str(string $str, int $len, string $encoding = 'UTF-8', string $suffix = '...'): string {
    return mb_cut($str, 0, $len, $encoding, $suffix);
}
?>

使用範例與測試

<?php
header('Content-Type: text/html; charset=UTF-8');

$utf8 = "你好世界 Hello World";
$gbk  = mb_convert_encoding($utf8, 'GBK', 'UTF-8');
$big5 = mb_convert_encoding($utf8, 'BIG-5', 'UTF-8');

echo "=== UTF-8 測試 ===\n";
echo "原文: $utf8\n";
echo "前6字: " . mb_cut($utf8, 0, 6) . "\n";           // 你好世界 H...
echo "倒數4字: " . mb_cut($utf8, -4) . "\n";            // o World
echo "第3-5字: " . mb_cut($utf8, 3, 3) . "\n";          // 世界

echo "\n=== GBK 測試 (指定編碼) ===\n";
echo "原文(GBK): " . bin2hex($gbk) . "\n";
echo "前4字: " . bin2hex(mb_cut($gbk, 0, 4, 'GBK')) . "\n"; // 你好世...

echo "\n=== 邊界保護 ===\n";
echo "長度不足: '" . mb_cut("Hi", 0, 10) . "'\n";       // Hi (無後綴)
echo "起始超界: '" . mb_cut("Hi", 5, 3) . "'\n";        // '' (空字串)
echo "負索引超界: '" . mb_cut("Hi", -10, 3) . "'\n";    // Hi (自動修正為 0)

echo "\n=== 實際場景:文章摘要 ===\n";
$article = "PHP 是一種廣泛使用的開源腳本語言,特別適合 Web 開發並可嵌入 HTML 中。";
echo "摘要(30字): " . cut_str($article, 30) . "\n";
// 輸出: PHP 是一種廣泛使用的開源腳本語言,特別適合 Web 開發並可嵌入 HTML...
?>

進階議題:效能與快取

頻繁呼叫 mb_convert_encoding 有效能開銷。高頻場景建議:

  1. 統一內部編碼為 UTF-8:資料庫、HTML、API 皆用 UTF-8,避免轉換。
  2. 預先轉碼:讀取 GBK/Big5 資料源時,一次性轉為 UTF-8 存入快取/資料庫。
  3. 靜態快取編碼檢測:若不確定編碼,可用 mb_detect_encoding 快取結果。

替代方案對比

函數編碼感知多位元組安全效能建議場景
substr否❌ (斷碼)極快純 ASCII / 二進制資料
mb_substr需指定✅中已知編碼、單一編碼環境
mb_cut (本文)自動轉換✅中 (含轉碼)混合編碼輸入、舊系統整合、快速開發
grapheme_substr (intl)UTF-8 only✅ (字素簇)較慢Emoji、複合字元 (如 旗幟、膚色修飾符) 正確計數

最佳實踐: 新專案強制全鏈路 UTF-8 (資料庫 utf8mb4、PHP default_charset、HTML <meta charset="utf-8">、HTTP Header)。只有在整合舊系統 (GBK/Big5) 時才需要跨編碼處理,且應在邊界層 (Controller/Service 入口) 統一轉碼,核心業務邏輯層僅處理 UTF-8。

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