Windows 控制台默认是使用系统默认字符集进行文字输出。例如,系统要支持简体中文,一般设置字符集为 936(GBK)。当遇到同时要输出其他语言时,就会出现乱码,例如,输出韩文。

解决这个问题,需要解决两个关键点:

  1. 要以 UTF-16 字符集输出;Windows 内部支持的 Unicode,实际上是 UTF-16,并不是 UCS2。
  2. 控制台要设置成支持 UTF-16 字符集的字体。

UTF-16 字符集输出问题,可以使用 SetConsoleOutputCP 函数将输出字符集改成 UTF-8。

字体问题,可以使用 SetCurrentConsoleFontEx 函数将控制台字体设置成 MS Gothic。Windows 7 下只能设置成 Lucida Console,但 Lucida Console 对 UTF-16 字符集支持的不好,中文可以,韩文不可以。不过字体再怎么设置,在 Windows 内置控制台上还是不支持 emoji,而在 Windows Terminal 上,都不需要改字体就全支持。

示例代码:

#include <iostream>
#include <locale>
#include <codecvt>
#include <windows.h>
using namespace std;
int main()
{
UINT oldcodepage = GetConsoleOutputCP();
CONSOLE_FONT_INFOEX oldFont;
ZeroMemory(&oldFont, sizeof(oldFont));
oldFont.cbSize = sizeof(oldFont);
GetCurrentConsoleFontEx(GetStdHandle(STD_OUTPUT_HANDLE), FALSE, &oldFont);
SetConsoleOutputCP(CP_UTF8);
CONSOLE_FONT_INFOEX font;
ZeroMemory(&font, sizeof(font));
font.cbSize = sizeof(CONSOLE_FONT_INFOEX);
font.dwFontSize.X = 11;
font.dwFontSize.Y = 18;
font.FontFamily = 54;
font.FontWeight = 400;
//wcscpy(font.FaceName, L"Lucida Console");
wcscpy(font.FaceName, L"MS Gothic");
font.nFont = 12;
SetCurrentConsoleFontEx(GetStdHandle(STD_OUTPUT_HANDLE), FALSE, &font);
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> u8cvt;
locale lc(locale(""), new std::codecvt_utf8_utf16<wchar_t>());
wcout.imbue(lc);
std::wstring wstr = L"中国";
std::string str = u8cvt.to_bytes(wstr);
wcout << L"abcd" << endl;
wcout << wstr << endl;
cout << str << endl;
printf("%s\n", str.c_str());
wstr = L"한식";
str = u8cvt.to_bytes(wstr);
wcout << wstr << endl;
cout << str << endl;
printf("%s\n", str.c_str());
wstr = L"✂️ Copy and 📋 Paste Emoji 👍";
str = u8cvt.to_bytes(wstr);
wcout << L"wcout << " << wstr << endl;
cout << "cout << " << str << endl;
printf("printf %s\n", str.c_str());
cin.get();
SetConsoleOutputCP(oldcodepage);
SetCurrentConsoleFontEx(GetStdHandle(STD_OUTPUT_HANDLE), FALSE, &oldFont);
return 0;
}

在控制台中输出的效果:

在 Windows Terminal 输出的效果:

以上代码在 Visual Studio 2017 编译通过,源代码以 UTF-8 BOM 编码格式存储。

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注