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

PHP 自動識別字符編碼並轉換為目標編碼(UTF-8/GBK/Big5)

     編輯:PHP 綜合知識

問題背景

iconv、mb_convert_encoding 都要求已知源編碼。但在爬蟲、郵件解析、舊系統對接等場景中,源編碼往往未知。本文提供一個基於正則的 UTF-8 檢測函數,自動識別並轉換至目標編碼。

核心函數

/**
 * 自動檢測編碼並轉換
 * @param string $string  待轉換字符串
 * @param string $target  目標編碼(默認 gbk)
 * @return string
 */
function detect_encoding($string, $target = 'gbk') {
    // RFC 3629 兼容的 UTF-8 正則(修正版)
    $utf8_regex = '%^(?:
        [\x09\x0A\x0D\x20-\x7E]              # ASCII
      | [\xC2-\xDF][\x80-\xBF]               # 2 字節
      | \xE0[\xA0-\xBF][\x80-\xBF]           # 3 字節首字節 E0
      | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}    # 3 字節常規
      | \xED[\x80-\x9F][\x80-\xBF]           # 3 字節代理區
      | \xF0[\x90-\xBF][\x80-\xBF]{2}        # 4 字節首字節 F0
      | [\xF1-\xF3][\x80-\xBF]{3}            # 4 字節常規
      | \xF4[\x80-\x8F][\x80-\xBF]{2}        # 4 字節尾部
    )*$%xs';

    $is_utf8 = (bool)preg_match($utf8_regex, $string);

    if ($is_utf8) {
        return ($target === 'utf8' || $target === 'utf-8')
            ? $string
            : mb_convert_encoding($string, $target, 'UTF-8');
    } else {
        // 非 UTF-8 按中文常見編碼嘗試轉換
        return mb_convert_encoding($string, $target, 'GBK,GB2312,BIG5');
    }
}

正則解析

  • %...%xs:x 忽略空白註釋,s 讓 . 匹配換行(此處未用)
  • 嚴格遵循 UTF-8 編碼規則,拒絕過長編碼、代理對、非最短編碼
  • 相比簡單的 preg_match('//u', $str),誤判率極低

使用示例

$tests = [
    '你好世界',                    // UTF-8
    iconv('UTF-8', 'GBK', '你好'), // GBK
    '测试',                        // 可能是 GBK/Big5
];

foreach ($tests as $t) {
    echo "原始: " . bin2hex($t) . "\n";
    echo "→ UTF-8: " . detect_encoding($t, 'utf-8') . "\n";
    echo "→ GBK:   " . detect_encoding($t, 'gbk') . "\n";
    echo "---\n";
}

局限性與改進方向

場景問題建議
極短字符串(<5字節)誤判率高結合 mb_detect_encoding 多重驗證
混合編碼文本無法逐字符識別按行/塊分割檢測
非中文語言(日文 Shift_JIS、韓文 EUC-KR)識別為非 UTF-8 後按中文編碼轉換會亂碼擴展檢測列表或引入 uchardet 庫
性能敏感場景正則匹配較慢僅在編碼未知時調用,已知編碼直接 mb_convert_encoding

生產環境推薦封裝

function smart_convert($str, $to = 'UTF-8') {
    // 1. 已知編碼優先(如 HTTP Content-Type、Meta Charset)
    // 2. 嘗試 mb_detect_encoding(需啟用 mbstring.encoding_translation)
    $detected = mb_detect_encoding($str, 'UTF-8, GBK, BIG5, ASCII', true);
    if ($detected) return mb_convert_encoding($str, $to, $detected);

    // 3. 兜底:正則檢測 UTF-8
    return detect_encoding($str, $to);
}
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved