我试图编写一个简单的命令行应用程序来学习日语,但好像无法打印Unicode字符。我错过了什么吗?
#include <iostream>
using namespace std;
int main()
{
wcout << L"こんにちは世界\n";
wcout << L"Hello World\n"
system("pause");
}
在这个例子中,只显示了“按任意键继续”。在Visual C++ 2013上进行了测试。
在Windows上这并不容易。即使你成功地将文本显示到Windows控制台,你仍需要配置cmd.exe才能够显示日语字符。
#include <iostream>
int main() {
std::cout << "こんにちは世界\n";
}
wcout << L"こんにちは世界\n";
wcout
使用其所附加的区域设置将wchar_t数据转换为char数据进行输出。问题在于默认语言环境仅必须支持基本源字符集中的字符,这甚至不包括所有ASCII字符,更不用说非ASCII字符了。wcout
处于错误状态。必须清除错误才能使wcout再次正常工作,这就是为什么第二个打印语句不输出任何内容的原因。
wcout
注入可成功转换字符的语言环境来解决一定范围内的字符限制。不幸的是,以此方式支持整个Unicode范围所需的编码是UTF-8;尽管Microsoft的流实现支持其他多字节编码,但它非常明确地不支持UTF-8。wcout.imbue(std::locale(std::locale::classic(), new std::codecvt_utf8_utf16<wchar_t>()));
SetConsoleOutputCP(CP_UTF8);
wcout << L"こんにちは世界\n";
在这里,wcout
将正确地将字符串转换为UTF-8,如果输出被写入文件而不是控制台,则文件将包含正确的UTF-8数据。然而,即使在此处配置为接受UTF-8数据,Windows控制台也不会接受以这种方式编写的UTF-8数据。
有几个选项:
Avoid the standard library entirely:
DWORD n;
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), L"こんにちは世界\n", 8, &n, nullptr);
Use non-standard magical incantation that will break standard code:
#include <fcntl.h>
#include <io.h>
_setmode(_fileno(stdout), _O_U8TEXT);
std::wcout << L"こんにちは世界\n";
After setting this mode std::cout << "Hello, World";
will crash.
Use a low level IO API along with manual conversion:
#include <codecvt>
#include <locale>
SetConsoleOutputCP(CP_UTF8);
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> convert;
std::puts(convert.to_bytes(L"こんにちは世界\n"));
使用任何一种方法,cmd.exe 将尽其所能显示正确的文本,我指的是它将显示无法阅读的方框。对于给定的字符串,会显示七个小方框。
你可以将文本从 cmd.exe 复制到记事本或其他应用程序中,以查看正确的字形。
有一篇关于在Windows控制台处理Unicode的文章
http://alfps.wordpress.com/2011/11/22/unicode-part-1-windows-console-io-approaches/
http://alfps.wordpress.com/2011/12/08/unicode-part-2-utf-8-stream-mode/
基本上,你可以通过实现自己的streambuf
来使用WriteConsoleW
,从而在Windows控制台中写入UTF-8(或任何其他Unicode),而不依赖于区域设置、控制台代码页甚至不使用宽字符。
这可能看起来并不是很直接,但它是一个方便和可重用的解决方案,还能为您提供可移植的utf8-everywhere风格的用户代码。请不要因我的英语而打我:)
或者您可以将Windows区域设置更改为日语。
chcp 65001
命令,Windows 操作系统无法将 Unicode 输出到终端窗口,即使使用该命令也不能保证完全正常工作。对于使用wcout
的 C++ 运行时我并不清楚它如何影响这种情况。 - Mark Ransom_setmode(_fileno(stdout), _O_WTEXT);
。当然,您还需要一个支持这些字符的字体(如果您没有这样的字体,仍然可以将输出重定向到文件并使用记事本打开)。有关详细信息,请参阅MSDN。 - Cubbi