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

J2ME GB2312 轉 UTF-8 完整解決方案:查表法與位元運算實作

     編輯:J2ME

背景與挑戰

J2ME 執行環境內部採用 UTF-8 編碼(且在字串前添雙字節長度前綴),但許多舊系統、伺服器端資料仍以 GB2312 傳輸。GB2312 與 Unicode/UTF-8 無直接數學映射關係,必須採用查表法轉換。

轉換流程

  1. 離線產生 GB2312 → Unicode 映射表(二進位檔 gb2u.dat,約 15 KB)。
  2. 執行期讀取映射表至記憶體。
  3. 逐字節解析輸入位元組陣列:
    • ASCII(< 0x80)直接複製。
    • 雙位元組 GB2312 依區位碼計算索引,查表得 Unicode。
    • 將 Unicode 以 UTF-8 編碼規則寫入輸出緩衝區。
  4. 以 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 裝置顯示

效能與優化建議

  • 映射表載入一次即可重複使用,建議做成 Singleton。
  • 頻繁轉換時重用 buffer 陣列減少 GC。
  • 若只需顯示而非網路傳輸,可直接輸出 Unicode char 陣列(見下一篇優化版)。

結語

此方案以 15 KB 映射表解決 J2ME 無 GB2312 解碼器的痛點,已在多款量產手機專案驗證穩定可用。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved