常見於:通訊錄索引、搜尋提示、資料庫模糊查詢優化、URL 別名生成等。需將中文字串轉為大寫拼音首字母,如「顧亮」→ GL。
GBK 編碼中,漢字佔兩個位元組。將兩字節合併為無號整數(zone * 256 + position),對應「區位碼」。GBK 漢字區範圍 0xB0A1 ~ 0xD7FA,按拼音首字母順序分區。建立首字母與區位碼上界的對映表,即可 O(1) 查詢。
import java.io.UnsupportedEncodingException;
public class PinyinInitials {
// 首字母對應的區位碼上界(含),按 GBK 編碼順序
private static final int[] BOUNDARIES = {
0xB0C5, 0xB2C1, 0xB4EE, 0xB6EA, 0xB7A2, 0xB8C1, 0xB9FE, 0xBBF7,
0xBFA6, 0xC0AC, 0xC2E8, 0xC4C3, 0xC5B6, 0xC5BE, 0xC6DA, 0xC8BB,
0xC8F6, 0xCBFA, 0xCDDA, 0xCEF4, 0xD1B9, 0xD4D1, 0xD7FA
};
private static final char[] INITIALS = "ABCDEFGHJKLMNOPQRSTWXYZ".toCharArray();
// 注意:無 I、U、V(標準拼音首字母無此字母)
/**
* 取得字串的拼音首字母大寫,非漢字原樣保留
*/
public static String toInitials(String str) {
if (str == null || str.isEmpty()) return "";
StringBuilder sb = new StringBuilder(str.length());
for (char c : str.toCharArray()) {
sb.append(getInitial(c));
}
return sb.toString().toUpperCase();
}
private static String getInitial(char c) {
byte[] bytes;
try {
bytes = String.valueOf(c).getBytes("GBK");
} catch (UnsupportedEncodingException e) {
return String.valueOf(c); // 環境不支援 GBK 時回退
}
if (bytes.length < 2) return String.valueOf(c); // ASCII 字元直接返回
// 合併為無號整數:(byte[0] & 0xFF) << 8 | (byte[1] & 0xFF)
int code = ((bytes[0] & 0xFF) << 8) | (bytes[1] & 0xFF);
if (code < 0xB0A1) return String.valueOf(c); // 非漢字區
// 二分查找首字母(線性查找亦可,只有 23 段)
for (int i = 0; i < BOUNDARIES.length; i++) {
if (code <= BOUNDARIES[i]) return String.valueOf(INITIALS[i]);
}
return String.valueOf(c); // 理論不會到達
}
// 測試
public static void main(String[] args) {
System.out.println(toInitials("顧亮")); // GL
System.out.println(toInitials("中華人民共和國")); // ZHRMGHG
System.out.println(toInitials("Hello 世界")); // HELLO SJ
}
}
byte 有號,轉無號需 & 0xFF,再移位合併。| 局限 | 說明 | 替代方案 |
|---|---|---|
| 僅支援 GBK 覆蓋字元 | 生僻字、港台繁體字、Emoji 會回退原字元 | 使用 ICU4J、pinyin4j 庫,支援 Unicode 全字集 |
| 多音字無法處理 | 如「長」僅返回 C(cháng),無法得知 zhǎng | 詞典分詞 + 上下文消歧(如 HanLP) |
| 依賴平台 GBK 支援 | 部分精簡 JVM 可能無 GBK 編碼器 | 內建編碼表,不依賴 Charset |
若需在無 GBK Charset 環境(如 Android、GraalVM Native)運行,可將上述 BOUNDARIES 表硬編碼,getBytes("GBK") 改為查表:預先建立 char -> int 映射(約 2萬條),佔用 ~200KB 記憶體,查詢極快且零依賴。
基於 GBK 區位碼的首字母轉換是「輕量、零依賴、效能極佳」的經典方案,適合純 ASCII+常用漢字場景。生產系統若涉及多音字、生僻字、國際化,建議引入成熟 NLP 庫(pinyin4j、HanLP、ICU4J),並在索引建立階段離線處理,避免即時查詢效能壓力。