8

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

#include <iostream>
using namespace std;

int main()
{
        wcout << L"こんにちは世界\n";
        wcout << L"Hello World\n"
        system("pause");
}

在此示例中,仅显示“按任意键继续”。在 Visual C++ 2013 上测试。

4

3 回答 3

7

这在 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 数据。但是,即使在此处配置为接受 UTF-8 数据,Windows 控制台也不会接受以这种方式写入的 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 或其他任何内容以查看正确的字形。

于 2013-09-19T23:00:28.643 回答
4

有一整篇关于在 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-流模式/

基本上,您可以实现自己的streambuffor std::cout(or std::wcout)WriteConsoleW并享受将 UTF-8(或任何您想要的 Unicode)写入 Windows 控制台,而不依赖于语言环境、控制台代码页,甚至不使用宽字符。
它可能看起来不是很简单,但它是一种方便且可重用的解决方案,它还能够为您提供可移植的 utf8-everywhere 风格的用户代码。请不要因为我的英语而打败我:)

于 2013-09-19T23:03:46.567 回答
-1

或者,您可以将 Windows 区域设置更改为日语。

于 2013-11-03T23:48:33.163 回答