原文《UTF-8與GB2312之間的互換》採用字串轉換模擬位元運算,效率低且有記憶體洩漏。本文改用直接位元運算實現 UTF-8 ↔ Unicode ↔ GB2312 轉換,大幅提升效能並修正資源管理問題。
UTF-8: 1110xxxx 10yyyyyy 10zzzzzz Unicode: xxxxyyyy yyzzzzzz
位元提取公式:
// pText[0] = 1110xxxx, pText[1] = 10yyyyyy, pText[2] = 10zzzzzz
// Unicode 低位元組在前 (Little Endian)
uchar[1] = ((pText[0] & 0x0F) << 4) | ((pText[1] >> 2) & 0x0F); // 高位元組
uchar[0] = ((pText[1] & 0x03) << 6) | (pText[2] & 0x3F); // 低位元組
// pchar[0] = Unicode 低位元組, pchar[1] = Unicode 高位元組
pOut[0] = 0xE0 | ((pchar[1] & 0xF0) >> 4);
pOut[1] = 0x80 | ((pchar[1] & 0x0F) << 2) | ((pchar[0] & 0xC0) >> 6);
pOut[2] = 0x80 | (pchar[0] & 0x3F);
class CChineseCodeLib {
public:
// UTF-8 → Unicode
static void UTF8ToUnicode(WCHAR* pOut, const char* pText) {
char* uchar = reinterpret_cast(pOut);
uchar[1] = ((pText[0] & 0x0F) << 4) | ((pText[1] >> 2) & 0x0F);
uchar[0] = ((pText[1] & 0x03) << 6) | (pText[2] & 0x3F);
}
// Unicode → UTF-8
static void UnicodeToUTF8(char* pOut, const WCHAR* pText) {
const char* pchar = reinterpret_cast(pText);
pOut[0] = 0xE0 | ((pchar[1] & 0xF0) >> 4);
pOut[1] = 0x80 | ((pchar[1] & 0x0F) << 2) | ((pchar[0] & 0xC0) >> 6);
pOut[2] = 0x80 | (pchar[0] & 0x3F);
}
// Unicode → GB2312 (系統 API)
static void UnicodeToGB2312(char* pOut, WCHAR uData) {
WideCharToMultiByte(CP_ACP, 0, &uData, 1, pOut, sizeof(WCHAR), NULL, NULL);
}
// GB2312 → Unicode (系統 API)
static void GB2312ToUnicode(WCHAR* pOut, const char* gbBuffer) {
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, gbBuffer, 2, pOut, 1);
}
// GB2312 → UTF-8 (字串版,修正記憶體洩漏)
static std::string GB2312ToUTF8(const char* pText, int len) {
std::string result;
result.reserve(len + len/2); // 預估空間
for (int i = 0; i < len; ) {
if (static_cast(pText[i]) < 0x80) { // ASCII
result.push_back(pText[i++]);
} else { // 雙位元組 GB2312
WCHAR wc;
GB2312ToUnicode(&wc, pText + i);
char buf[3];
UnicodeToUTF8(buf, &wc);
result.append(buf, 3);
i += 2;
}
}
return result; // RVO/移動語意,無洩漏
}
// UTF-8 → GB2312 (字串版)
static std::string UTF8ToGB2312(const char* pText, int len) {
std::string result;
result.reserve(len);
for (int i = 0; i < len; ) {
if (static_cast(pText[i]) < 0x80) { // ASCII
result.push_back(pText[i++]);
} else { // 三位元組 UTF-8
WCHAR wc;
UTF8ToUnicode(&wc, pText + i);
char buf[2];
UnicodeToGB2312(buf, wc);
result.append(buf, 2);
i += 3;
}
}
return result;
}
};
| 原版問題 | 本版改進 |
|---|---|
| 字串操作模擬位元運算 | 直接位元遮罩/位移,零分配、零分支預測失敗 |
| new/delete 手動管理,洩漏風險 | std::string RAII,自動生命週期管理 |
| 緩衝區大小固定,溢位風險 | reserve 預估 + append 動態增長,安全 |
| 函數傳回 char* 需呼叫端釋放 | 傳回 std::string,所有權語意清晰 |
| 無 const 正確性 | 參數加 const、static 成員函數、無狀態設計 |
std::string utf8 = "中文測試";
std::string gb = CChineseCodeLib::UTF8ToGB2312(utf8.c_str(), utf8.length());
// gb 現在包含 GB2312 編碼的 "中文測試"
std::string back = CChineseCodeLib::GB2312ToUTF8(gb.c_str(), gb.length());
// back == utf8
std::u8string、std::text_encoding (提案中) 原生支援位元運算版本不僅效能優越,程式碼更簡潔、語意更清晰,是編碼轉換常用工具庫的最佳實踐範本。