在中文排序、索引、搜索提示、文件命名等場景,常需將漢字轉為拼音首字母(簡拼)。本文提供基於 **GBK 編碼區位碼** 的純 Java 實現,無第三方依賴,覆蓋常用漢字區,附帶完整測試用例與擴展建議。
public class ChineseToPinyinInitials {
/** 將漢字字符串轉為大寫簡拼 (如 "顧亮" → "GL") */
public static String toInitials(String chinese) {
if (chinese == null || chinese.isEmpty()) return "";
StringBuilder sb = new StringBuilder(chinese.length());
for (char c : chinese.toCharArray()) {
sb.append(getInitial(c));
}
return sb.toString().toUpperCase();
}
/** 獲取單個字符的拼音首字母 (非漢字原樣返回) */
public static char getInitial(char c) {
// 1. 非漢字直接返回
if (c < 0x80) return c; // ASCII
// 2. 獲取 GBK 字節
byte[] bytes;
try {
bytes = String.valueOf(c).getBytes("GBK");
} catch (UnsupportedEncodingException e) {
return c; // 理論不會發生
}
// 3. 非雙字節 (非漢字) 返回原字符
if (bytes.length != 2) return c;
// 4. 計算區位碼 (無符號拼裝)
int zone = (bytes[0] & 0xFF) << 8 | (bytes[1] & 0xFF);
// 5. 區間映射表 (一級漢字區 0xB0A1 - 0xD7FE)
if (zone < 0xB0A1) return c; // 符號區
if (zone < 0xB0C5) return 'A';
if (zone < 0xB2C1) return 'B';
if (zone < 0xB4EE) return 'C';
if (zone < 0xB6EA) return 'D';
if (zone < 0xB7A2) return 'E';
if (zone < 0xB8C1) return 'F';
if (zone < 0xB9FE) return 'G';
if (zone < 0xBBF7) return 'H';
if (zone < 0xBFA6) return 'J'; // 無 I
if (zone < 0xC0AC) return 'K';
if (zone < 0xC2E8) return 'L';
if (zone < 0xC4C3) return 'M';
if (zone < 0xC5B6) return 'N';
if (zone < 0xC5BE) return 'O';
if (zone < 0xC6DA) return 'P';
if (zone < 0xC8BB) return 'Q';
if (zone < 0xC8F6) return 'R';
if (zone < 0xCBFA) return 'S';
if (zone < 0xCDDA) return 'T';
if (zone < 0xCEF4) return 'W'; // 無 U, V
if (zone < 0xD1B9) return 'X';
if (zone < 0xD4D1) return 'Y';
if (zone < 0xD7FA) return 'Z';
return c; // 二級漢字/擴展區,保守返回原字符
}
}
int zone = (bytes[0] & 0xFF) << 8 | (bytes[1] & 0xFF);
Java `byte` 有符號,`& 0xFF` 轉為無符號 0~255,再拼裝為 16 位區位碼。
基於 GBK 一級漢字區拼音排序邊界,例如:
public class ChineseToPinyinInitialsTest {
@Test
public void testBasic() {
assertEquals("GL", ChineseToPinyinInitials.toInitials("顧亮"));
assertEquals("ZHONGGUO", ChineseToPinyinInitials.toInitials("中國"));
assertEquals("BJ", ChineseToPinyinInitials.toInitials("北京"));
assertEquals("HELLO", ChineseToPinyinInitials.toInitials("HELLO")); // 英文保持
assertEquals("A1B", ChineseToPinyinInitials.toInitials("A1B")); // 數字保持
}
@Test
public void testBoundary() {
// 區間邊界字符測試 (需確保文件編碼為 GBK 或使用 Unicode 轉義)
// 啊 U+554A GBK B0A1 -> A
// 坐 U+5750 GBK D7F9 -> Z
}
}
| 局限 | 說明 | 解決方案 |
|---|---|---|
| 僅覆蓋一級漢字 (3755 字) | 二級漢字、擴展字、生僻字返回原字符 | 引入 pinyin4j、HanLP、ICU4J 支持 7萬+ 字符 |
| 多音字無法處理 | 如「行」→ X/H、「長」→ C/Z | 需詞典/語境分析,上述庫均支持 |
| 依賴 GBK 編碼環境 | 運行環境必須支持 GBK (Windows 默認支持,Linux 容器需安裝 locales) | 改用 Unicode 碼點映射表 (如 pinyin4j 內部實現) |
| 無法處理姓名/地名專有讀音 | 如「單」姓讀 Shàn、曾國藩「曾」讀 Zēng | 需專業詞典庫 |