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

Java Big5 轉 GB2312 編碼轉換完整實作

     編輯:關於JSP

傳統中文編碼互轉:Big5 ↔ GB2312 核心算法解析

在早期華語系統整合專案中,繁體 (Big5) 與簡體 (GB2312) 編碼共存是常態。雖然現代系統普遍採用 Unicode (UTF-8),但維護舊系統、處理舊資料遷移時,仍需掌握這兩種編碼的直接互轉邏輯。本文深度解析一個純 Java 實作的 Big5 轉 GB2312 轉換器。

核心原理:查表法映射

Big5 與 GB2312 皆為雙位元組編碼,但碼表排列方式截然不同,無簡單數學公式可直接換算。業界標準做法是建立映射對照表 (mapping table),查表轉換。

完整程式碼實作

package com.charset.converter;

import java.io.*;

public class Big5ToGb2312Converter {
    // 映射表檔案:每筆對應佔 2 位元組 (GB2312 碼)
    private static final String MAP_FILE = "bg-gb.tab";
    private static byte[] mapData;  // 載入記憶體的映射表

    static {
        loadMappingTable();
    }

    /** 載入映射表至記憶體 */
    private static void loadMappingTable() {
        try (FileInputStream fis = new FileInputStream(MAP_FILE)) {
            int len = fis.available();
            mapData = new byte[len];
            fis.read(mapData);
        } catch (Exception e) {
            throw new RuntimeException("載入編碼映射表失敗: " + MAP_FILE, e);
        }
    }

    /**
     * 計算 Big5 碼在映射表中的位移索引
     * @param big5Code Big5 雙位元組碼值 (高位在前)
     * @return 映射表中的位元組索引
     */
    private static int calculateOffset(int big5Code) {
        int high = (big5Code >>> 8) & 0xFF;
        int low  = big5Code & 0xFF;

        // Big5 碼區結構調整
        high -= 0xA1;
        if (low <= 0x7E) {
            low -= 0x40;
        } else {
            low -= (0xA1 - 0x7E - 1) + 0x40;
        }

        // 每個字元佔 2 位元組 (GB2312 雙位元組)
        return 2 * (high * 157 + low);
    }

    /**
     * 核心轉換邏輯:直接操作位元組陣列
     * @param srcBytes Big5 編碼的位元組陣列 (會被直接修改)
     * @return 轉換後的 GB2312 位元組陣列 (同一物件)
     */
    public static byte[] convert(byte[] srcBytes) {
        int i = 0;
        while (i < srcBytes.length) {
            int high = srcBytes[i] & 0xFF;
            
            // 判斷是否為 Big5 雙位元組字元首位 (0xA1-0xFE)
            if (high >= 0xA1 && high <= 0xFE) {
                i++;
                if (i >= srcBytes.length) break;
                
                int low = srcBytes[i] & 0xFF;
                
                // 合法 Big5 低位元組範圍: 0x40-0x7E, 0xA1-0xFE
                if (low < 0x40 || low > 0xFE || (low > 0x7E && low < 0xA1)) {
                    i++;
                    continue;
                }

                int offset = calculateOffset((high << 8) | low);
                
                // 從映射表取得 GB2312 碼,覆寫原位元組
                srcBytes[i - 1] = mapData[offset];
                srcBytes[i]     = mapData[offset + 1];
                i++;
            } else {
                // ASCII 或單位元組字元,保持不變
                i++;
            }
        }
        return srcBytes;
    }

    /**
     * 字串層級轉換介面
     * @param big5Str Big5 編碼的字串
     * @return GB2312 編碼的字串
     */
    public static String convert(String big5Str) {
        if (big5Str == null || big5Str.isEmpty()) return big5Str;
        
        try {
            // 1. 字串 → Big5 位元組陣列
            byte[] bytes = big5Str.getBytes("Big5");
            // 2. 位元組陣列轉換
            convert(bytes);
            // 3. 位元組陣列 → GB2312 字串
            return new String(bytes, "GB2312");
        } catch (Exception e) {
            throw new RuntimeException("編碼轉換失敗", e);
        }
    }

    // 測試主程式
    public static void main(String[] args) {
        String traditional = "繁體中文測試:台灣、香港";
        String simplified = convert(traditional);
        System.out.println("原文 (Big5): " + traditional);
        System.out.println("轉換 (GB2312): " + simplified);
    }
}

關鍵技術細節解析

1. 映射表格式 (bg-gb.tab)

  • 二進位檔案,無標頭
  • 按 Big5 碼序排列,每筆 2 位元組 = 對應的 GB2312 碼
  • 總大小約:13,000+ 字元 × 2 位元組 ≈ 26KB

2. Big5 碼區結構與索引計算

Big5 編碼分區:

  • 高位元組: 0xA1–0xFE (共 94 區)
  • 低位元組: 0x40–0x7E (區內前 63 碼) + 0xA1–0xFE (區內後 94 碼) = 157 碼/區

索引公式:offset = 2 × [(high - 0xA1) × 157 + adjustedLow]

3. 位元組陣列就地修改

為節省記憶體與 GC 壓力,轉換直接在原 byte[] 上覆寫,適合大量文字處理場景。

現代替代方案

JDK 內建 Charset 機制已支援雙向轉換,且效能更好、維護性更高:

// 推薦做法:使用標準 API
String gb2312Str = new String(big5Str.getBytes("Big5"), "GB2312");

// 或使用 CharsetDecoder/Encoder 流式處理大檔案
CharsetDecoder decoder = Charset.forName("Big5").newDecoder();
CharsetEncoder encoder = Charset.forName("GB2312").newEncoder();

適用場景建議

場景建議方案
新專案開發統一使用 UTF-8,避免編碼轉換
舊系統維護、資料遷移JDK 內建 Charset API
極度效能敏感、嵌入式環境本文查表法 (無物件建立開銷)
特殊字元映射需求 (異體字、造字)自訂映射表 + 查表法

理解底層編碼轉換機制,不僅能解決亂碼疑難雜症,更能在字元處理、國際化 (i18n) 領域建立堅實技術直覺。

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