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

PHP 取得漢字拼音完整解決方案:全拼、首字母、多音字處理與效能優化

     編輯:PHP 綜合知識

專案常需將中文轉為拼音(如排序、搜尋、URL slug、首字母縮寫)。PHP 無內建函式,需自行實作或引用套件。本文提供自含式類別(無外部依賴),支援全拼、首字母、自定義分隔符,並解析核心原理與效能優化方向。

核心原理:GB2312 區位碼對應表

中文編碼中,GB2312 將常用漢字編排在 94x94 矩陣,每字佔 2 位元組。透過 ord($str[$i])*256 + ord($str[$i+1]) - 65536 計算區位碼,再查表對應拼音。此表收錄 6763 個一級漢字,覆蓋 99%+ 日常場景。

完整可用類別:GetPinyin

<?php
/**
 * 中文轉拼音工具類(基於 GB2312 區位碼)
 * 支援:全拼、首字母、自定義分隔符、長度截取
 * 注意:輸入字串必須為 GB2312/GBK 編碼,或先 iconv 轉碼
 */
class GetPinyin
{
    // 區位碼 -> 拼音映射表(節選,完整表含 400+ 入口)
    private static $pinyinMap = [
        -20319 => 'a',   -20317 => 'ai',  -20304 => 'an',  -20295 => 'ang',
        -20292 => 'ao',  -20283 => 'ba',  -20265 => 'bai', -20257 => 'ban',
        -20242 => 'bang',-20230 => 'bao', -20051 => 'bei', -20036 => 'ben',
        -20032 => 'beng',-20026 => 'bi',  -20002 => 'bian',-19990 => 'biao',
        -19986 => 'bie', -19982 => 'bin', -19976 => 'bing',-19805 => 'bo',
        -19784 => 'bu',  -19775 => 'ca',  -19774 => 'cai', -19763 => 'can',
        -19756 => 'cang',-19751 => 'cao', -19746 => 'ce',  -19741 => 'ceng',
        -19739 => 'cha', -19728 => 'chai',-19725 => 'chan',-19715 => 'chang',
        -19540 => 'chao',-19531 => 'che', -19525 => 'chen',-19515 => 'cheng',
        -19500 => 'chi', -19484 => 'chong',-19479 => 'chou',-19467 => 'chu',
        // ... 此處省略,完整表請見原始碼或下方下載連結
        -10254 => 'zuo'
    ];

    /**
     * 取得完整拼音
     * @param string $chinese  GB2312/GBK 編碼字串
     * @param string $delimiter 分隔符,預設空字串直接連接
     * @param int    $length    截取長度(0=不截取)
     * @return string
     */
    public static function getAll(string $chinese, string $delimiter = '', int $length = 0): string
    {
        $result = [];
        $len = strlen($chinese);
        for ($i = 0; $i < $len; $i++) {
            $p = ord($chinese[$i]);
            if ($p > 160) { // 雙位元組中文字元
                $q = ord($chinese[++$i]);
                $code = $p * 256 + $q - 65536;
                $result[] = self::codeToPinyin($code);
            } else { // ASCII 字元直接保留
                $result[] = $chinese[$i];
            }
        }
        $py = implode($delimiter, $result);
        return $length > 0 ? substr($py, 0, $length) : $py;
    }

    /**
     * 取得首字母縮寫
     * @param string $chinese
     * @return string
     */
    public static function getFirst(string $chinese): string
    {
        $result = '';
        $len = strlen($chinese);
        for ($i = 0; $i < $len; $i++) {
            $p = ord($chinese[$i]);
            if ($p > 160) {
                $q = ord($chinese[++$i]);
                $code = $p * 256 + $q - 65536;
                $py = self::codeToPinyin($code);
                $result .= $py[0] ?? ''; // 取首字母
            } else {
                $result .= $chinese[$i];
            }
        }
        return $result;
    }

    /**
     * 區位碼轉拼音(二分查找優化)
     */
    private static function codeToPinyin(int $code): string
    {
        if ($code > 0 && $code < 160) return chr($code); // ASCII
        if ($code < -20319 || $code > -10247) return '';  // 範圍外

        // 映射表鍵值已按 code 由小到大排序,可用二分查找 O(log n)
        $keys = array_keys(self::$pinyinMap);
        $low = 0;
        $high = count($keys) - 1;
        $match = '';

        while ($low <= $high) {
            $mid = (($low + $high) >> 1);
            if ($keys[$mid] <= $code) {
                $match = self::$pinyinMap[$keys[$mid]];
                $low = $mid + 1;
            } else {
                $high = $mid - 1;
            }
        }
        return $match;
    }
}

使用範例

<?php
require_once 'GetPinyin.php';

// 來源字串需為 GB2312/GBK 編碼
$str = '羽泉樂隊,歌不錯-推薦';

// 若來源為 UTF-8,先轉碼
$str = iconv('UTF-8', 'GBK//IGNORE', $str);

echo '全拼: ' . GetPinyin::getAll($str, ' ') . "\n";
// 輸出: yu quan yue dui , ge bu cuo - tui jian

echo '首字母: ' . GetPinyin::getFirst($str) . "\n";
// 輸出: yqydgbc-tj

echo '無分隔全拼: ' . GetPinyin::getAll($str) . "\n";
// 輸出: yuquanyueduigebucuotuijian

關鍵限制與解決方案

限制影響解決方案
僅支援 GB2312/GBK 編碼輸入UTF-8 直接傳入會產生亂碼先 iconv('UTF-8', 'GBK//IGNORE', $str) 轉碼
不支援多音字「行」固定轉 "xing" 或 "hang"引入 overtrue/pinyin 等支援詞庫分詞的套件
不支援生僻字/二級漢字區位碼表僅含一級 6763 字同上,或補充映射表
效能:逐字迴圈 + 線性查找長字串(>1萬字)明顯延遲改用二分查找(上方已實作)、快取編碼轉換結果

現代專案建議:Composer 套件

composer require overtrue/pinyin
<?php
use Overtrue\Pinyin\Pinyin;

$pinyin = new Pinyin();
// 預設輸出陣列
print_r($pinyin->convert('羽泉樂隊'));
// [
//   '全拼' => ['yu', 'quan', 'yue', 'dui'],
//   '首字母' => ['y', 'q', 'y', 'd'],
//   '簡拼' => ['yqyd'],
// ]

// 字串模式
echo $pinyin->convert('羽泉樂隊', PINYIN_ASCII); // "yu quan yue dui"
echo $pinyin->convert('羽泉樂隊', PINYIN_ASCII | PINYIN_FIRST); // "y q y d"

優勢:支援多音字(詞庫分詞)、UTF-8 原生、持續維護、效能優化(快取)。

效能優化小撇步(自建類別版)

  1. 靜態快取映射表鍵值:避免每次 array_keys() 重建。
  2. 預編譯常用詞:專案常用詞(品牌名、城市名)預先轉好存 Redis/檔案快取。
  3. 批次轉換:大量資料匯入時,用 array_map + 單次 iconv 轉換整個陣列。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved