在編碼轉換(iconv、mb_convert_encoding)前檢測字符串是否已為 UTF-8,可避免重複轉碼導致亂碼。本文提供正則嚴格驗證與 mb_detect_encoding 兩種方案,並分析優缺點。
<?php
function is_utf8($string) {
// 來源:W3C 國際化 QA
return (bool) preg_match('%^(?:
[\x09\x0A\x0D\x20-\x7E] # ASCII
| [\xC2-\xDF][\x80-\xBF] # 非超長 2 字節
| \xE0[\xA0-\xBF][\x80-\xBF] # 排除超長 3 字節
| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # 直通 3 字節
| \xED[\x80-\x9F][\x80-\xBF] # 排除代理區
| \xF0[\x90-\xBF][\x80-\xBF]{2} # 平面 1-3
| [\xF1-\xF3][\x80-\xBF]{3} # 平面 4-15
| \xF4[\x80-\x8F][\x80-\xBF]{2} # 平面 16
)*$%xs', $string);
}
?>
✅ 優點:完全符合 UTF-8 規範,拒絕非法字節序列(如超長編碼、代理對)。
⚠️ 缺點:正則複雜,效率略低於內建函數。
<?php
function mb_is_utf8($string) {
return mb_detect_encoding($string, 'UTF-8', true) === 'UTF-8';
}
// 多編碼檢測示例
$encoding = mb_detect_encoding($text, ['UTF-8', 'GBK', 'GB2312'], true);
switch ($encoding) {
case 'UTF-8': /* 已是 UTF-8 */ break;
case 'GBK': $text = iconv('GBK', 'UTF-8', $text); break;
default: /* 未知編碼處理 */ break;
}
?>
✅ 優點:C 層實現極快、API 簡潔、支持多編碼列表按順序嘗試。
⚠️ 缺點:mbstring 擴展非核心編譯(需 --enable-mbstring),極短字符串可能誤判。
| 方法 | 耗時 | 備註 |
|---|---|---|
| preg_match 正則 | ~1.8s | 純 PHP 正則引擎 |
| mb_detect_encoding | ~0.3s | C 內建函數 |
mb_detect_encoding($str, 'UTF-8', true)(第三參數 true 開啟嚴格模式)。mb_is_utf8 先篩,可疑再走正則)。is_utf8()。<?php
// 輸入「呵」→ 輸出 %E5%91%B5
echo urlencode("呵"); // 內部按腳本編碼(通常UTF-8)轉換
?>