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

C語言實現中文編碼轉換:GB2312、GBK、BIG5 互轉核心技術詳解

     編輯:關於C語言

C語言實現中文編碼轉換:GB2312、GBK、BIG5 互轉核心技術詳解

中文編碼轉換是跨平台、跨地區中文應用開發的必經之路。主流內碼包括簡體 GB2312、GBK 及繁體 BIG5。早期靠巨大碼表硬轉,資源消耗大且不完美。Windows API 提供 MultiByteToWideChar 與 WideCharToMultiByte 兩大核心函數,配合 Unicode 作為中介,可高效、準確完成各編碼間互轉,無需外部碼表。

核心轉換原理

雙階段轉換模型:

  1. 源編碼 → Unicode (UTF-16):MultiByteToWideChar(CodePage, ...)
  2. Unicode → 目標編碼:WideCharToMultiByte(CodePage, ...)

關鍵代碼頁常量:

  • 936 = GBK (兼容 GB2312)
  • 950 = BIG5
  • 20936 = GB2312 (部分系統支持)
  • 54936 = GB18030
  • 1200 = UTF-16
  • 65001 = UTF-8

四大核心轉換函數實現

1. BIG5 → GBK

void BIG5_to_GBK(char *buf) {
    if (!buf || !*buf) return;
    int len = strlen(buf);
    wchar_t *wbuf = (wchar_t*)malloc((len + 1) * sizeof(wchar_t));
    if (!wbuf) return;

    // BIG5(950) -> Unicode
    int wlen = MultiByteToWideChar(950, 0, buf, len, wbuf, len + 1);
    if (wlen == 0) { free(wbuf); return; }

    // Unicode -> GBK(936)
    BOOL usedDefault = FALSE;
    int rlen = WideCharToMultiByte(936, 0, wbuf, wlen, buf, len + 1, "?", &usedDefault);
    if (rlen > 0) buf[rlen] = '\0';
    free(wbuf);
}

2. GBK → BIG5


void GBK_to_BIG5(char *buf) {
    if (!buf || !*buf) return;
    int len = strlen(buf);
    wchar_t *wbuf = (wchar_t*)malloc((len + 1) * sizeof(wchar_t));
    if (!wbuf) return;

    // GBK(936) -> Unicode
    int wlen = MultiByteToWideChar(936, 0, buf, len, wbuf, len + 1);
    if (wlen == 0) { free(wbuf); return; }

    // Unicode -> BIG5(950)
    BOOL usedDefault = FALSE;
    int rlen = WideCharToMultiByte(950, 0, wbuf, wlen, buf, len + 1, "?", &usedDefault);
    if (rlen > 0) buf[rlen] = '\0';
    free(wbuf);
}

3. GB2312 → GBK (利用 LCMapString)


void GB2312_to_GBK(char *buf) {
    if (!buf || !*buf) return;
    int len = strlen(buf);
    
    // 使用簡體中文排序標識
    LCID lcid = MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_CHINESE_PRC);
    
    // 先查所需緩衝區大小
    int need = LCMapString(lcid, LCMAP_TRADITIONAL_CHINESE, buf, len, NULL, 0);
    if (need == 0) return;
    
    char *tmp = (char*)malloc(need + 1);
    if (!tmp) return;
    
    LCMapString(lcid, LCMAP_TRADITIONAL_CHINESE, buf, len, tmp, need);
    strncpy(buf, tmp, need);
    buf[need] = '\0';
    free(tmp);
}

4. GBK → GB2312


void GBK_to_GB2312(char *buf) {
    if (!buf || !*buf) return;
    int len = strlen(buf);
    
    // 使用 BIG5 排序標識進行簡化轉換
    LCID lcid = MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_CHINESE_BIG5);
    
    int need = LCMapString(lcid, LCMAP_SIMPLIFIED_CHINESE, buf, len, NULL, 0);
    if (need == 0) return;
    
    char *tmp = (char*)malloc(need + 1);
    if (!tmp) return;
    
    LCMapString(lcid, LCMAP_SIMPLIFIED_CHINESE, buf, len, tmp, need);
    strncpy(buf, tmp, need);
    buf[need] = '\0';
    free(tmp);
}

組合轉換:GB2312 ↔ BIG5

無直接 API 時,以 GBK 為中介:

  • GB2312 → BIG5:GB2312_to_GBK() → GBK_to_BIG5()
  • BIG5 → GB2312:BIG5_to_GBK() → GBK_to_GB2312()

關鍵注意事項

  1. 緩衝區安全:輸出長度可能超過輸入,建議分配 2 * len + 2 字節緩衝區,或先用 NULL 目標查詢所需大小。
  2. 錯誤處理:檢查 API 返回值,GetLastError() 獲取詳細錯誤碼。
  3. 不可用 String.c_str() 作輸入:返回的是 const char*,轉換需可寫緩衝區。
  4. 線程安全:API 本身線程安全,但共享緩衝區需自行同步。
  5. 現代替代方案:跨平台項目首選 iconv、ICU 庫或 C++17 std::wstring_convert (已棄用) / std::from_chars 配合第三方庫。

完整測試示例


#include 
#include 
#include 
#include 

// 上述四個函數實現...

int main() {
    char buf[256] = "中華人民共和國"; // 假設源文件為 GB2312/GBK 編碼保存
    
    printf("原始: %s\n", buf);
    
    // GB2312 -> GBK
    strcpy(buf, "中華人民共和國");
    GB2312_to_GBK(buf);
    printf("GBK: %s\n", buf);
    
    // GB2312 -> BIG5 (經 GBK 中轉)
    strcpy(buf, "中華人民共和國");
    GB2312_to_GBK(buf);
    GBK_to_BIG5(buf);
    printf("BIG5: %s\n", buf);
    
    return 0;
}

總結: Windows 平台下,利用 MultiByteToWideChar/WideCharToMultiByte 配合 Unicode 中介,是實現 GB2312/GBK/BIG5 互轉的標準、高效、免碼表方案。掌握代碼頁常量與雙階段轉換模型,即可輕鬆應對中文編碼互轉需求。

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