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

C++ 讀取 GBK/UTF-8 混合編碼文本:區分漢字與 ASCII 字符的正確姿勢(雙字節特徵判斷)

     編輯:程式設計疑難解答

問題本質

GBK 編碼下,漢字佔 2 字節,首字節高位為 1(≥ 0x81),尾字節範圍 0x40–0xFE(含 0x48 'H')。單字節讀取時,尾字節會被誤判為 ASCII 字符,導致「錒」(0xE5 0x48) 後半字節 0x48 被當作 'H' 寫入拼音串。

核心修正邏輯:優先識別雙字節漢字

while (!ifs.eof()) {
    ifs.read(&word, 1);
    if (isChineseLeadByte(word)) {          // 1. 先判斷是否為漢字首字節
        char byte2;
        ifs.read(&byte2, 1);                // 2. 直接讀取尾字節,組成完整漢字
        chinese = string(1, word) + byte2;  // 3. 確信是漢字,無需二次判斷
        // 處理漢字-拼音映射...
    }
    else if (isLetterOrNumber(word)) {      // 4. 排除漢字後,再處理 ASCII
        pinyin += word;
    }
    // 其他控制字符處理...
}

漢字首字節判斷函數

bool isChineseLeadByte(unsigned char c) {
    // GBK: 0x81-0xFE 為首字節範圍(排除 0x7F 控制字符)
    return c >= 0x81 && c <= 0xFE;
}

// UTF-8 版本(首字節高位模式)
bool isUTF8LeadByte(unsigned char c) {
    return (c & 0x80) != 0;  // 1xxxxxxx 為多字節序列首字節
}

完整修正版關鍵片段

// 原邏輯錯誤:逐字節判斷,尾字節 0x48 被誤判為 'H'
// 修正:檢測到首字節 → 強制讀取下一字節組合 → 確認為漢字

if (isChineseLeadByte(word)) {
    char next;
    ifs.read(&next, 1);
    string hanzi; hanzi += word; hanzi += next;
    
    table[hanzi] = pinyin;
    ofs.write(hanzi.c_str(), 2);
    ofs.write(pinyin.c_str(), pinyin.size());
    ofs.write("\r\n", 2);
    
    chinese.clear();
    pinyin.clear();  // 重置拼音緩衝
}
else if (isLetterOrNumber(word)) {
    pinyin += word;
}
else if (word == '\r') {
    ifs.read(&word, 1); // 吞掉 \n
    pinyin.clear();
}

編碼層面的根治建議

  1. 統一轉 UTF-8:用 `iconv` 或 `MultiByteToWideChar` 將文件整體轉為 UTF-8,再按 Unicode 碼點處理,徹底規避雙字節分割問題。
  2. 使用成熟庫:ICU (International Components for Unicode) 提供健壯的邊界檢測、分詞、轉碼功能。
  3. C++17 `` + ``**(C++20 棄用)或第三方 `utf8cpp` 庫處理 UTF-8 字符串迭代。

關鍵原則總結

「多字節編碼下,必須按字符邊界讀取,而非按字節逐個判斷。」
檢測到 Lead Byte → 原子性讀取完整字符 → 語義處理,中間不插入單字節判斷邏輯。

掌握「首字節特徵 → 整體讀取 → 語義處理」三步法,GBK/UTF-8/Big5 等所有多字節編碼文本解析都能游刃有餘。

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