J2ME 執行環境內部採用 UTF-8 編碼(且在字串前添雙字節長度前綴),但許多舊系統、伺服器端資料仍以 GB2312 傳輸。GB2312 與 Unicode/UTF-8 無直接數學映射關係,必須採用查表法轉換。
gb2u.dat,約 15 KB)。new String(buffer, "UTF-8") 產生最終字串。HGB2312 關鍵程式碼public class HGB2312 {
private final byte[] map = new byte[15228];
private byte[] buffer;
private int index;
public HGB2312() throws Exception {
InputStream is = getClass().getResourceAsStream("/gb2u.dat");
is.read(map); is.close();
}
public String gb2utf8(byte[] gb) throws Exception {
buffer = new byte[gb.length + gb.length/2 + 3];
index = 0;
for (int i=0; i<gb.length; ) {
if (gb[i] >= 0) { fillBuffer(gb[i++]); }
else {
int h = 256 + gb[i++];
int l = 256 + gb[i++];
h -= 0xA0 + 1; l -= 0xA0 + 1;
int ind, c;
if (h < 9) {
ind = (h*94 + l) << 1;
c = (byte2Int(map[ind]) << 8) | byte2Int(map[ind+1]);
fillBuffer(c);
} else if (h <= 14) { fillBuffer(0); } // 非漢字區
else if (h > 14) {
h -= 6;
ind = (h*94 + l) << 1;
c = (byte2Int(map[ind]) << 8) | byte2Int(map[ind+1]);
fillBuffer(c);
} else { fillBuffer(0); }
}
}
return new String(buffer, 0, index, "UTF-8");
}
private void fillBuffer(int unicode) {
if (unicode <= 0x7F) { buffer[index++] = (byte)unicode; }
else if (unicode <= 0x7FF) {
buffer[index++] = (byte)(0xC0 | (unicode >> 6));
buffer[index++] = (byte)(0x80 | (unicode & 0x3F));
} else { // <= 0xFFFF
buffer[index++] = (byte)(0xE0 | (unicode >> 12));
buffer[index++] = (byte)(0x80 | ((unicode >> 6) & 0x3F));
buffer[index++] = (byte)(0x80 | (unicode & 0x3F));
}
}
private int byte2Int(byte b) { return b < 0 ? 256+b : b; }
}
參考 Herong Yang 開源產生器,依 GB2312 分區(01-09 區、16-55 區)將 Unicode 依序寫入。表大小 15228 bytes,含 6768 個漢字與符號,完全符合 J2ME 記憶體限制。
byte[] gbBytes = "中文測試".getBytes("GB2312"); // 需在支援 GB2312 的環境取得
HGB2312 converter = new HGB2312();
String utf8Str = converter.gb2utf8(gbBytes); // 可在任何 J2ME 裝置顯示
buffer 陣列減少 GC。此方案以 15 KB 映射表解決 J2ME 無 GB2312 解碼器的痛點,已在多款量產手機專案驗證穩定可用。