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

PHP 截取中英文混合字符串:正確區分全半角避免亂碼

     編輯:PHP 綜合知識

問題根源

在 GB2312/GBK 編碼下,英文字符佔 1 字節(半角,ASCII < 128),中文字符佔 2 字節(全角,高位字節 > 128)。若直接用 substr() 按字節截取,極易將一個漢字「切成兩半」,導致頁面顯示亂碼()。

核心判斷邏輯

遍歷字符串前 $length 字節,統計高位字節(> 128)的個數:

  • 若為偶數,說明截斷點落在字符邊界,可直接截取。
  • 若為奇數,說明截斷點在某個漢字的「中間」,需向後多取 1 字節,湊齊雙字節。

通用截取函數

<?php
/**
 * 安全截取 GB2312/GBK 編碼字符串
 * @param string $str 輸入字符串
 * @param int $len  期望顯示長度(按字節計)
 * @param string $suffix 截斷後綴,默認 "..."
 * @return string
 */
function chgTitle($str, $len = 46, $suffix = '...') {
    if (strlen($str) <= $len) return $str;

    $highBytes = 0;
    for ($i = 0; $i < $len; $i++) {
        if (ord($str[$i]) > 128) $highBytes++;
    }

    // 奇數說明切在漢字中間,向後補一位
    $cutLen = ($highBytes % 2 === 0) ? $len : $len + 1;
    return substr($str, 0, $cutLen) . $suffix;
}

// 測試
$title = "這是一個測試標題Test123";
echo chgTitle($title, 10); // 輸出:這是一個測試...
echo chgTitle($title, 11); // 輸出:這是一個測試標...
?>

原理解析

// 假設 $str = "中A文" (GBK: D6 D0 41 CE C4)
// 字節索引: 0 1 2 3 4
// ord:      D6 D0 41 CE C4
// >128:     是 是 否 是 是

// 截取前 3 字節 (len=3)
// 高位計數 = 2 (偶數) -> 直接截取 -> "中A" (正確)
// 截取前 4 字節 (len=4)
// 高位計數 = 3 (奇數) -> 補 1 -> 取 5 字節 -> "中A文" (正確)
// 若不補位直接取 4 字節 -> "中A文" 的前半個 "文" -> 亂碼

進階:支援 UTF-8 的 mb_substr 方案

現代項目建議統一使用 UTF-8 編碼,並直接用多字節字符串函數:

<?php
// PHP 內置,正確按字符而非字節計數
$str = "這是測試Test";
echo mb_substr($str, 0, 6, 'UTF-8') . '...'; // 輸出:這是測試T...

// 封裝通用函數(自動檢測編碼或指定 UTF-8)
function mb_chgTitle($str, $len = 46, $suffix = '...', $encoding = 'UTF-8') {
    if (mb_strlen($str, $encoding) <= $len) return $str;
    return mb_substr($str, 0, $len, $encoding) . $suffix;
}
?>

總結

編碼環境推薦函數關鍵點
GB2312/GBK (舊項目)自定義 chgTitle()統計高位字節奇偶,補位湊齊雙字節
UTF-8 (新項目)mb_substr() / mb_strimwidth()按字符計數,無需手動處理字節邊界

最佳建議:新項目全棧使用 UTF-8(數據庫、頁面、PHP 文件編碼),徹底避開字節截取陷阱。

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