打印Unicode字符C++

jef*_*yer 8 c++ unicode

我正在尝试编写一个简单的命令行应用程序来自学日语,但似乎无法打印Unicode字符.我错过了什么?

#include <iostream>
using namespace std;

int main()
{
        wcout << L"???????\n";
        wcout << L"Hello World\n"
        system("pause");
}
Run Code Online (Sandbox Code Playgroud)

在此示例中,仅显示"按任意键继续".在Visual C++ 2013上测试过.

bam*_*s53 7

这在Windows上并不容易.即使您设法将文本发送到Windows控制台,仍然需要配置cmd.exe才能显示日语字符.


#include <iostream>

int main() {
  std::cout << "???????\n";
}
Run Code Online (Sandbox Code Playgroud)

这适用于以下任何系统:

  • 编译器的源代码和执行编码包括字符.
  • 输出设备(例如,控制台)期望文本与编译器的执行编码具有相同的编码.
  • 可以使用具有相应字符的字体(通常不是问题).

目前大多数平台默认使用UTF-8进行所有这些编码,因此可以使用与上述类似的代码支持整个Unicode范围.不幸的是,Windows不是这些平台之一.

wcout << L"???????\n";
Run Code Online (Sandbox Code Playgroud)

在这一行中,字符串文字数据(在编译时)从源编码转换为执行宽编码,然后(在运行时)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";
Run Code Online (Sandbox Code Playgroud)

这里wcout将正确地将字符串转换为UTF-8,如果输出被写入文件而不是控制台,那么该文件将包含正确的UTF-8数据.但是,Windows控制台即使在此处配置为接受UTF-8数据,也不会接受以这种方式写入的UTF-8数据.


有几个选择:

  • 完全避免使用标准库:

    DWORD n;
    WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), L"???????\n", 8, &n, nullptr);
    
    Run Code Online (Sandbox Code Playgroud)
  • 使用会破坏标准代码的非标准魔法咒语:

    #include <fcntl.h>
    #include <io.h>
    
    _setmode(_fileno(stdout), _O_U8TEXT);
    std::wcout << L"???????\n";
    
    Run Code Online (Sandbox Code Playgroud)

    设置此模式后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"));
    
    Run Code Online (Sandbox Code Playgroud)

使用任何这些方法,cmd.exe将尽可能显示正确的文本,我的意思是它将显示不可读的框.七个小盒子,用于给定的字符串.

                            小盒子

您可以将文本从cmd.exe复制到notepad.exe或其他任何内容以查看正确的字形.