漢字在 GB2312 中按拼音排序,每個字佔 2 字節(高位 0xA1-0xF7,低位 0xA1-0xFE)。通過計算區位碼對應拼音首字母或完整拼音。
class Pinyin {
private static $pinyinMap = []; // 拼音 => 區位碼起始值
public static function init() {
// 完整映射表省略(約 400+ 條)
// 格式: 'a' => -20319, 'ai' => -20317, ...
self::$pinyinMap = [
'a' => -20319, 'ai' => -20317, 'an' => -20304, /* ... */ 'zuo' => -10254
];
arsort(self::$pinyinMap); // 降序,便於查找
}
public static function getPinyin($string, $charset = 'UTF-8') {
if (empty(self::$pinyinMap)) self::init();
if ($charset !== 'GB2312') {
$string = iconv($charset, 'GB2312//IGNORE', $string);
}
$result = '';
$len = strlen($string);
for ($i = 0; $i < $len; $i++) {
$ord = ord($string[$i]);
if ($ord < 160) { // ASCII
$result .= $string[$i];
} else { // 雙字節漢字
$q = ord($string[++$i]);
$gbCode = $ord * 256 + $q - 65536; // 負數區位碼
foreach (self::$pinyinMap as $py => $code) {
if ($code <= $gbCode) {
$result .= $py;
break;
}
}
}
}
return preg_replace('/[^a-z0-9]/i', '', $result);
}
public static function getInitials($string, $charset = 'UTF-8') {
// 類似邏輯,只取首字母
// 利用區位碼範圍直接判斷首字母 A-Z
}
}
<?php
require 'Pinyin.php';
$name = '張三豐';
echo Pinyin::getPinyin($name); // zhangsanfeng
echo Pinyin::getInitials($name); // zsf
// 數據庫關鍵字字段
$product = '蘋果手機14 Pro';
$keyword = Pinyin::getPinyin($product) . ' ' . Pinyin::getInitials($product);
// 存入 keyword 字段: "pingguoshouji14pro pg sj"
// 搜索時匹配:用戶輸 "pg" 或 "pingguo" 均可命中
| 庫 | 特點 | 安裝 |
|---|---|---|
| overtrue/pinyin | 最流行、支持多音字、分詞、首字母、Laravel 集成 | composer require overtrue/pinyin |
| jiannei/chinese-pinyin | 輕量、無依賴、性能好 | composer require jiannei/chinese-pinyin |
| pinyin/pinyin | 基於詞庫、準確率高 | composer require pinyin/pinyin |