【问题标题】:Correct and crossplatform way to use UTF-8 in C++ streams在 C++ 流中使用 UTF-8 的正确跨平台方式
【发布时间】:2014-06-28 08:20:24
【问题描述】:

我从this answer to the similar question 了解到,Visual C++ STL 实现中有一个still unfixed bug。 因此,不可能只写std::cout << raw_utf8_string << std::endl 并在 Windows 下享受漂亮的 UTF-8 字符;(

注意:我的测试程序是 here

但也许有一个非常简单易懂的解决方法来处理这个问题? 我的想法:制作一个像cout_ex 这样的包装类,它将使用Windows API WriteConsoleA 用于控制台输出。
在它的构造函数中做this:

#ifdef _WIN32
if (IsValidCodePage (CP_UTF8))
{
    if (!SetConsoleCP (CP_UTF8))
        std::cout << "Could not set console input code page to UTF-8" << std::endl;
    if (!SetConsoleOutputCP (CP_UTF8))
        std::cout << "Could not set console output code page to UTF-8" << std::endl;
}
else
    std::cout << "UTF-8 code page is not supported in your system" <<   std::endl;
#endif

在输出方法中这样做:

char const raw_utf8_text[] = "Blåbærsyltetøy! кошка!";

DWORD raw_written = 0;
WriteConsoleA (GetStdHandle (STD_OUTPUT_HANDLE), raw_utf8_text, std::strlen (raw_utf8_text), &raw_written, NULL);

并且不要忘记在 src 的开头使用未记录的 Visual C++ pragma:

#pragma execution_character_set("utf-8")

但也许有一个更清晰的解决方案 :) 即使使用一些外部库,如 Poco/Boost/等。

我尝试阅读那些文章12,但我发现这种方式太复杂了。 附言重写的流类也应该将控制台字体设置为 Unicode 字体。
附言软件版本:Windows 8 x64 + Visual C++ 2013 Express。

【问题讨论】:

  • 我没有深入检查SetConsoleCP,但一般的口头禅是在 Windows 上 UTF-8 不是受支持的 CP(CP_UTF8 主要用于 MultiByteToWideCharWideCharToMultiByte )。在 Windows 上使用 UTF-8 的典型方式是在 API 边界处转换为 WCHAR
  • 您可能会更幸运地将控制台 CP 设置为 CP_UNICODE,然后手动将 UTF-8 转换为 UTF-16(请记住 CP_UNICODE==UTF-16)。
  • @MatteoItalia 所以在 Windows 下我只能转换为 UTF-16 并使用 std::wcout 进行输出?
  • @rodrigo 我会检查这个。但是,Unicode != UTF-16 :) 为什么微软这么认为,我不明白...
  • @Axilles:我知道,这就是为什么我说CP_UNICODE,而不是Unicode。更奇怪的是为什么他们认为 ANSI 等于......有用的东西。

标签: c++ utf-8 stl iostream


【解决方案1】:

您应该在输出流中注入适当的 codecvt_facet。

std::locale loc;
string encoding=getOutputEncoding(); // 
loc=std::locale(loc, createCodecvt(encoding));
cout.imbue(loc);
cout.rdbuf().imbue(loc);

Complete code here

此方面应将内部编码转换为外部编码。由于 STL 实现中的some bugs,如果内部存储格式是单字节或多字节编码,这可能是不可能的。有一个解决方法 - 使用 filestreambuf 而不是默认输出缓冲区。

您可能必须实现自己的 codecvt_facet 或使用我的 iconv wrapper

总的来说,我仍然建议使用宽字符进行内部处理。这样您甚至可以避免任何额外的转换(系统默认转换除外)。

【讨论】:

  • 那么,哪里没有没有转换没有办法输出UTF-8呢?任何黑客,解决方法 - 无论如何。这是问题的主要目标
  • 当然有。 First question you linked 提到 fputs 方法工作得很好。恕我直言,您可以在标准输出上使用 fstreambuf(在灌输语言环境中禁用转换设置)。但是,您会在配置错误的控制台上得到垃圾。
  • 我检查了fputs - 它工作正常。谢谢!因此,只有 Microsoft STL 流实现存在 UTF-8 问题。我在哪里可以阅读更多关于它的原因?目前我很难理解:(
  • 但是你自己链接了这个问题!有详尽的解释。只需按照链接。特别是connect.microsoft.com/VisualStudio/feedback/details/431244/…
  • 嗯,看来我今天太累了 :D 对不起。我需要休息,慢慢阅读,消化我读到的东西。如此多的信息 - 同时在 Linux 中一切正常。
猜你喜欢
  • 2014-10-26
  • 2011-10-21
  • 1970-01-01
  • 2011-04-18
  • 2011-05-29
  • 2015-01-03
  • 1970-01-01
  • 2015-10-24
  • 2018-10-25
相关资源
最近更新 更多