array_combine 相容性處理漢字在 GB2312 編碼中佔兩個位元組,區碼 16-87 位,位碼 1-94 位。透過公式:
區位碼 = (高位元組 - 0xA0) * 100 + (低位元組 - 0xA0)
GB2312 內碼 = (區碼 * 256) + 位碼 - 65536
建立 拼音首字母 ↔ 區位碼範圍 對應表,二分查找或線性掃描確定拼音。
$_DataKey = "a|ai|an|ang|ao|ba|bai|ban|bang|bao|..."; // 400+ 拼音
$_DataValue = "-20319|-20317|-20304|-20295|-20292|..."; // 對應區位碼數值
兩字串以 | 分隔,explode() 後組合成關聯陣列 $_Data['a'] = -20319,並以 arsort() 由大排到小,利於後續查找。
function _U2_Utf8_Gb($_C)
{
// 將 Unicode 碼位轉為 UTF-8 位元組序列
if ($_C < 0x80) return chr($_C);
elseif ($_C < 0x800) {
return chr(0xC0 | $_C >> 6) . chr(0x80 | $_C & 0x3F);
} elseif ($_C < 0x10000) {
return chr(0xE0 | $_C >> 12) . chr(0x80 | $_C >> 6 & 0x3F) . chr(0x80 | $_C & 0x3F);
} elseif ($_C < 0x200000) {
return chr(0xF0 | $_C >> 18) . chr(0x80 | $_C >> 12 & 0x3F) . chr(0x80 | $_C >> 6 & 0x3F) . chr(0x80 | $_C & 0x3F);
}
// 再透過 iconv 轉為 GB2312
return iconv('UTF-8', 'GB2312', $_String);
}
function Pinyin($_String, $_Code = 'gb2312')
{
// 1. 非 GB2312 輸入先轉碼
if ($_Code != 'gb2312') $_String = _U2_Utf8_Gb($_String);
$_Res = '';
for ($i = 0; $i < strlen($_String); $i++) {
$_P = ord($_String[$i]);
// 2. 判斷是否為漢字雙位元組
if ($_P > 160) {
$_Q = ord($_String[++$i]);
$_P = $_P * 256 + $_Q - 65536; // 計算區位碼數值
}
// 3. 查表取得拼音
$_Res .= _Pinyin($_P, $_Data);
}
// 4. 只保留字母數字
return preg_replace("/[^a-z0-9]*/", '', $_Res);
}
function _Pinyin($_Num, $_Data)
{
if ($_Num > 0 && $_Num < 160) return chr($_Num); // ASCII 直接回傳
if ($_Num < -20319 || $_Num > -10247) return ''; // 超出漢字範圍
foreach ($_Data as $k => $v) {
if ($v <= $_Num) break; // 因已由大排小,第一個 <= 即為所屬拼音區間
}
return $k;
}
// GB2312 輸入(預設)
echo Pinyin('中文'); // zhongwen
// UTF-8 輸入(第二參數任意非 'gb2312' 值)
echo Pinyin('張三', 'utf-8'); // zhangsan
echo Pinyin('張三', 1); // 同樣生效
chang,無法依語境判斷 zhangiconv 轉碼會丟失超集字元iconv 擴充模組啟用新專案建議使用 overtrue/pinyin (Composer 套件),支援:
composer require overtrue/pinyin
use Overtrue\Pinyin\Pinyin;
$pinyin = new Pinyin();
$pinyin->convert('張三'); // ['zhang', 'san']