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 编码格式存储。

发表回复

您的电子邮箱地址不会被公开。