我正在尝试编写一个简单的命令行应用程序来自学日语,但似乎无法打印Unicode字符。我错过了什么?
#include <iostream>
using namespace std;
int main()
{
wcout << L"こんにちは世界\n";
wcout << L"Hello World\n"
system("pause");
}
在此示例中,仅显示“按任意键继续”。在Visual C ++ 2013上测试。
答案 0 :(得分:6)
这在Windows上并不容易。即使您设法将文本发送到Windows控制台,仍然需要配置cmd.exe才能显示日语字符。
#include <iostream>
int main() {
std::cout << "こんにちは世界\n";
}
这适用于以下任何系统:
目前,大多数平台默认使用UTF-8进行所有这些编码,因此可以使用与上述类似的代码支持整个Unicode范围。不幸的是,Windows不是这些平台之一。
wcout << L"こんにちは世界\n";
在这一行中,字符串文字数据(在编译时)从源编码转换为执行范围编码,然后(在运行时)wcout
使用它所灌注的语言环境来转换wchar_t数据char数据输出。出现问题的地方是,默认语言环境只需要支持基本源字符集中的字符,这些字符集甚至不包括所有ASCII字符,更不用说非ASCII字符。
因此转换会导致错误,导致wcout
处于错误状态。在wcout再次运行之前必须清除错误,这就是第二个print语句不输出任何内容的原因。
您可以通过使用可成功转换字符的区域设置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数据。但是,Windows控制台即使在此处配置为接受UTF-8数据,也不会接受以这种方式写入的UTF-8数据。
有几个选择:
完全避免使用标准库:
DWORD n;
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), L"こんにちは世界\n", 8, &n, nullptr);
使用违反标准代码的非标准魔法咒语:
#include <fcntl.h>
#include <io.h>
_setmode(_fileno(stdout), _O_U8TEXT);
std::wcout << L"こんにちは世界\n";
设置此模式后,std::cout << "Hello, World";
将崩溃。
使用低级IO API和手动转换:
#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复制到notepad.exe或其他任何内容以查看正确的字形。
答案 1 :(得分:3)
有关于在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
为std::cout
(或std::wcout
)实现自己的WriteConsoleW
并享受编写UTF-8(或您想要的任何Unicode)到Windows控制台,不依赖于区域设置,控制台代码页,甚至不使用宽字符
它可能看起来不是很简单,但它是方便且可重复使用的解决方案,它还能够为您提供便携式utf8无处不在的用户代码。请不要因为我的英语而打败我:)
答案 2 :(得分:-1)
或者您可以将Windows区域设置更改为日语。