不是所有的简体中文字符都可以映射到 BIG5(虽然包括了很大一部分),也不是所有的繁体中文字符都可以映射到 GBK 等编码。
不过微软提供了简繁转换接口,LCMapStringEx
,可以将 Unicode 字符串中的简体和繁体仅限转换(不包括当地特有词汇)。
因此,你可以:
- BIG5 繁体字符转到 Unicode
- 使用
LCMapStringEx
将 Unicode 字符串的繁体字符映射到简体字符
- 最后将这段 Unicode 字符串转换到 GBK。
测试代码:
#include <string>
#include <iostream>
#include <windows.h>
#include <ctype.h>
#include <stdio.h>
// 以十六进制视图打印
void hexdump(const void* ptr, int buflen) {
auto* buf = (const unsigned char*)ptr;
int i, j;
for (i = 0; i < buflen; i += 16) {
printf("%06x: ", i);
for (j = 0; j < 16; j++)
if (i + j < buflen)
printf("%02x ", buf[i + j]);
else
printf(" ");
printf(" ");
for (j = 0; j < 16; j++)
if (i + j < buflen)
printf("%c", isprint(buf[i + j]) ? buf[i + j] : '.');
printf("\n");
}
}
template <typename CONTAINER>
void hexdump(CONTAINER& str)
{
hexdump(reinterpret_cast<const void*>(str.data()), str.size() * sizeof(str[0]));
}
// 代码页信息
// https://learn.microsoft.com/wind ... de-page-identifiers
constexpr int kCodePageGB2312 = 936; // 简体 (GB2312)
constexpr int kCodePageGB18030 = 54936; // 简体 (GB18030)
constexpr int kCodePageBig5 = 950; // 繁体
// 简单的 Ansi/Unicode 互转
std::wstring A2W(const std::string& ansi, int codePage = CP_ACP)
{
int len = MultiByteToWideChar(codePage, 0, ansi.c_str(), -1, NULL, 0);
std::wstring wide(len, 0);
MultiByteToWideChar(codePage, 0, ansi.c_str(), -1, &wide[0], len);
return wide;
}
std::string W2A(const std::wstring& wide, int codePage = CP_ACP)
{
int len = WideCharToMultiByte(codePage, 0, wide.c_str(), -1, NULL, 0, nullptr, NULL);
std::string ansi(len, 0);
WideCharToMultiByte(codePage, 0, wide.c_str(), -1, &ansi[0], len, nullptr, NULL);
return ansi;
}
int main()
{
std::wstring text_src = L"吾爱破解论坛 - 爱飞的猫";
// 简转繁
std::wstring text_trad(text_src.size(), 0);
LCMapStringEx(LOCALE_NAME_INVARIANT, LCMAP_TRADITIONAL_CHINESE, text_src.c_str(), text_src.size(), &text_trad[0], text_trad.size(), nullptr, nullptr, 0);
std::wcout << L"繁体后: " << text_trad << L'\n';
std::cout << "trad(bytes)\n";
hexdump(text_trad);
// 繁转简
std::wstring text_simp(text_trad.size(), 0);
LCMapStringEx(LOCALE_NAME_INVARIANT, LCMAP_SIMPLIFIED_CHINESE, text_trad.c_str(), text_trad.size(), &text_simp[0], text_simp.size(), nullptr, nullptr, 0);
std::wcout << L"简体后: " << text_trad << L'\n';
std::cout << "simp(bytes)\n";
hexdump(text_simp);
// 繁(Unicode) 转 BIG5
auto text_trad_big5 = W2A(text_trad, kCodePageBig5);
std::cout << "text_trad_big5(bytes)\n";
hexdump(text_trad_big5);
// 简(Unicode) 转 BIG5
auto text_simp_big5 = W2A(text_simp, kCodePageBig5);
std::cout << "text_simp_big5(bytes)\n";
hexdump(text_simp_big5);
// 繁(Unicode) 转 GB18030
auto text_trad_GB18030 = W2A(text_trad, kCodePageGB18030);
std::cout << "text_trad_GB18030(bytes)\n";
hexdump(text_trad_GB18030);
// 简(Unicode) 转 GB18030
auto text_simp_GB18030 = W2A(text_simp, kCodePageGB18030);
std::cout << "text_simp_GB18030(bytes)\n";
hexdump(text_simp_GB18030);
return 0;
}
转换结果:
trad(bytes)
000000: 3e 54 1b 61 34 78 e3 89 d6 8a c7 58 20 00 2d 00 >T.a4x.....X .-.
000010: 20 00 1b 61 db 98 84 76 93 8c ..a...v..
simp(bytes)
000000: 3e 54 31 72 34 78 e3 89 ba 8b 5b 57 20 00 2d 00 >T1r4x....[W .-.
000010: 20 00 31 72 de 98 84 76 2b 73 .1r...v+s
text_trad_big5(bytes)
000000: a7 5e b7 52 af 7d b8 d1 bd d7 be c2 20 2d 20 b7 .^.R.}...... - .
000010: 52 ad b8 aa ba bf df 00 R.......
text_simp_big5(bytes)
000000: a7 5e 3f af 7d b8 d1 3f 3f 20 2d 20 3f 3f aa ba .^?.}..?? - ??..
000010: 3f 00 ?.
text_trad_GB18030(bytes)
000000: ce e1 90 db c6 c6 bd e2 d5 93 89 af 20 2d 20 90 ............ - .
000010: db ef 77 b5 c4 d8 88 00 ..w.....
text_simp_GB18030(bytes)
000000: ce e1 b0 ae c6 c6 bd e2 c2 db cc b3 20 2d 20 b0 ............ - .
000010: ae b7 c9 b5 c4 c3 a8 00 ........
放到十六进制编辑器看看(调整好代码页):
可以看到如果不进行字符映射,转换到 BIG5 编码后会缺字(显示为问号)。