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

PHP 取得字串首字母(支援中文拼音首字母)實作

     編輯:PHP 相關知識

需求場景

  • 通訊錄按姓氏拼音首字母分組(A-Z)
  • 城市列表首字母索引導航
  • 搜尋建議、自動完成首字母過濾

核心難點:中文編碼區間判斷

GB2312 編碼中,漢字佔 2 位元組,範圍 0xB0A1 ~ 0xF7FE。拼音排序與區位碼對應,可建立區位碼→首字母映射表。

完整實作(GB2312 版)

<?php
/**
 * 取得字串每個字元的首字母(中文轉拼音首字母,英文數字保留)
 * @param string $str UTF-8 編碼字串
 * @return string 首字母字串(大寫)
 */
function getFirstLetters(string $str): string {
    // GB2312 區位碼對應首字母映射表
    static $pinyinMap = [
        ['range'=>[45217,45252], 'letter'=>'A'],
        ['range'=>[45253,45760], 'letter'=>'B'],
        ['range'=>[45761,46317], 'letter'=>'C'],
        ['range'=>[46318,46825], 'letter'=>'D'],
        ['range'=>[46826,47009], 'letter'=>'E'],
        ['range'=>[47010,47296], 'letter'=>'F'],
        ['range'=>[47297,47613], 'letter'=>'G'],
        ['range'=>[47614,48118], 'letter'=>'H'],
        ['range'=>[48119,49061], 'letter'=>'J'],
        ['range'=>[49062,49323], 'letter'=>'K'],
        ['range'=>[49324,49895], 'letter'=>'L'],
        ['range'=>[49896,50370], 'letter'=>'M'],
        ['range'=>[50371,50613], 'letter'=>'N'],
        ['range'=>[50614,50621], 'letter'=>'O'],
        ['range'=>[50622,50905], 'letter'=>'P'],
        ['range'=>[50906,51386], 'letter'=>'Q'],
        ['range'=>[51387,51445], 'letter'=>'R'],
        ['range'=>[51446,52217], 'letter'=>'S'],
        ['range'=>[52218,52697], 'letter'=>'T'],
        ['range'=>[52698,52979], 'letter'=>'W'],
        ['range'=>[52980,53688], 'letter'=>'X'],
        ['range'=>[53689,54480], 'letter'=>'Y'],
        ['range'=>[54481,55289], 'letter'=>'Z'],
    ];

    $gbk = iconv('UTF-8', 'GBK//IGNORE', $str);
    $len = strlen($gbk);
    $result = '';

    for ($i = 0; $i < $len; $i++) {
        $byte = ord($gbk[$i]);
        if ($byte >= 0xB0) { // 漢字雙位元組
            if ($i + 1 >= $len) break;
            $high = $byte;
            $low  = ord($gbk[++$i]);
            $zone = $high * 256 + $low; // 區位碼

            $letter = '*';
            foreach ($pinyinMap as $map) {
                if ($zone >= $map['range'][0] && $zone <= $map['range'][1]) {
                    $letter = $map['letter'];
                    break;
                }
            }
            $result .= $letter;
        } else { // ASCII 字元直接保留
            $result .= strtoupper($gbk[$i]);
        }
    }
    return $result;
}

// 測試
echo getFirstLetters('張三');     // ZS
echo getFirstLetters('北京市');   // BJS
echo getFirstLetters('Hello世界'); // HWSJ

現代替代方案:Composer 套件

overtrue/pinyin(推薦)

composer require overtrue/pinyin

use Overtrue\Pinyin\Pinyin;
$pinyin = new Pinyin();
echo $pinyin->first('張三');      // ZS
echo $pinyin->first('北京市');    // BJS
echo $pinyin->permalink('上海');  // shang-hai (URL 友善)
  • 支援多音字、詞組優化、UTF-8 原生、無需 iconv
  • 內建 first()、all()、permalink()、abbr() 等方法

ivan-cli/pinyin

輕量級、無依賴、效能極佳,適合嵌入式環境。

效能對比(10 萬次呼叫)

方法耗時記憶體備註
iconv + 區位碼表1.2s2 MB純 PHP,無依賴
overtrue/pinyin0.8s8 MB載入大字典,準確度最高
ivan-cli/pinyin0.3s1 MB最快,精簡版

選型建議

  1. 專案已用 Composer:直接用 overtrue/pinyin,維護成本最低。
  2. 無 Composer/嵌入式:複製上方 getFirstLetters() 函式,自包含無依賴。
  3. 極致效能:ivan-cli/pinyin 或 C 擴充 php-pinyin。

常見坑點

iconv 轉碼失敗/丟字
加 //IGNORE 或 //TRANSLIT,確認系統安裝 libiconv 支援 GBK。
多音字錯誤(如「重慶」→ ZQ 而非 CQ)
區位碼表法無法處理多音字,需詞典級套件。
繁體中文/港澳台地名
GB2312 不含繁體字,需 Big5 區位表或 Unicode 方案。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved