在繁體中文 (Big5) 與簡體中文 (GB2312/GBK) 系統間交換資料時,常需進行編碼與字形雙重轉換。Windows 提供 MultiByteToWideChar、WideCharToMultiByte 與 LCMapString 三大 API,串聯即可完成「Big5 → Unicode → GB 繁體 → GB 簡體」完整流程。本文提供可直接部署的 C++ 封裝函數。
Big5 → [MultiByteToWideChar(CP=950)] → Unicode
↓
GB 繁體 ← [WideCharToMultiByte(CP=936)] ← Unicode
↓
GB 簡體 ← [LCMapString(LCMAP_SIMPLIFIED_CHINESE)] ← GB 繁體
#include
#include
#include
// 輔助:安全釋放陣列
template
struct ArrayDeleter { void operator()(T* p) { delete[] p; } };
// Big5 → GB 簡體
std::string Big5ToGbSimplified(const std::string& big5Str)
{
if (big5Str.empty()) return "";
// 1. Big5 → Unicode
int unicodeLen = MultiByteToWideChar(950, 0, big5Str.c_str(), -1, nullptr, 0);
if (unicodeLen == 0) return "";
std::unique_ptr> unicodeBuf(new wchar_t[unicodeLen]);
MultiByteToWideChar(950, 0, big5Str.c_str(), -1, unicodeBuf.get(), unicodeLen);
// 2. Unicode → GB 繁體 (CP 936)
int gbLen = WideCharToMultiByte(936, 0, unicodeBuf.get(), -1, nullptr, 0, nullptr, nullptr);
if (gbLen == 0) return "";
std::unique_ptr> gbTradBuf(new char[gbLen]);
WideCharToMultiByte(936, 0, unicodeBuf.get(), -1, gbTradBuf.get(), gbLen, nullptr, nullptr);
// 3. GB 繁體 → GB 簡體
std::unique_ptr> gbSimpBuf(new char[gbLen]);
LCMapString(0x0804, LCMAP_SIMPLIFIED_CHINESE, gbTradBuf.get(), -1, gbSimpBuf.get(), gbLen);
return std::string(gbSimpBuf.get());
}
// GB 簡體 → Big5
std::string GbSimplifiedToBig5(const std::string& gbSimpStr)
{
if (gbSimpStr.empty()) return "";
// 1. GB 簡體 → GB 繁體
int gbLen = MultiByteToWideChar(936, 0, gbSimpStr.c_str(), -1, nullptr, 0);
if (gbLen == 0) return "";
std::unique_ptr> gbTradBuf(new char[gbLen * 2]); // 繁體可能較長
LCMapString(0x0804, LCMAP_TRADITIONAL_CHINESE, gbSimpStr.c_str(), -1, gbTradBuf.get(), gbLen * 2);
// 2. GB 繁體 → Unicode
int unicodeLen = MultiByteToWideChar(936, 0, gbTradBuf.get(), -1, nullptr, 0);
if (unicodeLen == 0) return "";
std::unique_ptr> unicodeBuf(new wchar_t[unicodeLen]);
MultiByteToWideChar(936, 0, gbTradBuf.get(), -1, unicodeBuf.get(), unicodeLen);
// 3. Unicode → Big5
int big5Len = WideCharToMultiByte(950, 0, unicodeBuf.get(), -1, nullptr, 0, nullptr, nullptr);
if (big5Len == 0) return "";
std::unique_ptr> big5Buf(new char[big5Len]);
WideCharToMultiByte(950, 0, unicodeBuf.get(), -1, big5Buf.get(), big5Len, nullptr, nullptr);
return std::string(big5Buf.get());
}
| API | 關鍵參數 | 說明 |
|---|---|---|
| MultiByteToWideChar | CodePage=950/936 | 950=Big5, 936=GBK/GB2312 |
| WideCharToMultiByte | CodePage=936/950 | 輸出目標編碼頁 |
| LCMapString | Locale=0x0804 (zh-CN) | LCMAP_SIMPLIFIED_CHINESE / LCMAP_TRADITIONAL_CHINESE |
若專案已設定 Character Set = Use Unicode,可直接使用 CString 簡化:
CString Big5ToGb(const CString& big5)
{
// Big5 → Unicode
int len = MultiByteToWideChar(950, 0, big5, -1, NULL, 0);
CStringW unicode; wchar_t* buf = unicode.GetBuffer(len);
MultiByteToWideChar(950, 0, big5, -1, buf, len); unicode.ReleaseBuffer();
// Unicode → GB 簡體 (一次完成:LCMapString 支援 Unicode 輸入)
len = LCMapString(0x0804, LCMAP_SIMPLIFIED_CHINESE, unicode, -1, NULL, 0);
CString gbSimp; wchar_t* out = gbSimp.GetBuffer(len);
LCMapString(0x0804, LCMAP_SIMPLIFIED_CHINESE, unicode, -1, out, len); gbSimp.ReleaseBuffer();
return gbSimp;
}
注意: LCMapString 在 Unicode 版本可直接處理字形轉換,無需中繼 GB 繁體步驟,但 ANSI 專案必須經過完整三階段。
2x 空間或先呼叫 API 取得長度再配置。new/delete。Windows 核心 API 提供完整的字碼頁轉換與字形對應能力,組合 MultiByteToWideChar、WideCharToMultiByte、LCMapString 即可實作健全的繁簡轉換。現代專案建議改用 .NET Encoding.Convert 或 ICU 庫,但在純 C++/MFC 維護專案中,上述封裝函數仍是最輕量、零依賴的解決方案。