針對 GBK、GB2312、UTF-8、UTF-16 等編碼,提供一個函數 getChinese() 從混合字串中過濾出中文字元。原理利用中文編碼中首字節高位為 1 ( > 0xA0 ) 的特徵,配合編碼對應的字節長度截取。
function getChinese($string, $encoding = 'GBK') {
$byteLen = [
'GBK' => 2,
'GB2312' => 2, // 實際同 GBK
'UTF-8' => 3, // 中文常為 3 字節
'UTF-16' => 4,
];
$len = $byteLen[strtoupper($encoding)] ?? 2;
$result = '';
$strLen = strlen($string);
for ($i = 0; $i < $strLen; $i++) {
$char = $string[$i];
if (ord($char) > 0xA0) { // 高位元組特徵
$result .= substr($string, $i, $len);
$i += $len - 1;
}
}
return $result;
}
// 測試
$str = 'Hello 世界 123 你好';
echo getChinese($str, 'UTF-8'); // 輸出: 世界你好 (若檔案為 UTF-8 編碼)
| 問題 | 說明 |
|---|---|
| 編碼假設固定字節長 | UTF-8 中文 3 字節,但英文 1 字節、Emoji 4 字節,固定長度會誤切 |
| 無法處理混合編碼 | 字串必須為單一已知編碼 |
| 誤判擴展 ASCII | 0xA0~0xFF 在單字節編碼中也是合法字元 |
// 使用 mbstring (需安裝擴展)
function getChineseMb($str) {
return preg_replace('/[^\p{Han}]/u', '', $str); // 僅保留漢字
}
// 或使用正則直接匹配 Unicode 範圍
function getChineseRegex($str) {
preg_match_all('/[\x{4e00}-\x{9fa5}]+/u', $str, $m);
return implode('', $m[0]);
}
$str = 'Hello 世界 🌍 你好';
echo getChineseMb($str); // 世界你好
echo getChineseRegex($str); // 世界你好
mb_ereg_replace、mb_substr 等函數原生支援多位元組編碼。舊專案若無 mbstring,可考慮 iconv 轉 UTF-8 後再用正則,或引入 polyfill-mbstring。