如何使用C++ 11语言环境设施将UTF-8用作字符串的内部表示?

Xir*_*dus 7 c++ encoding locale utf-8 c++11

我正在编写一个处理文件和目录的可移植库.我想使用UTF-8作为输入(目录路径)和输出(文件路径).问题是,Windows让我可以选择使用UTF-16-UCS-2和代码页.所以我必须将我的所有UTF-8字符串转换为UTF-16,将它们传递给WinAPI,然后将结果转换回UTF-8.C++ 11似乎<locale>只为此提供了库,除了我所理解的,没有任何预定义的特化使用UTF-8作为内部(即我的)编码 - 最接近的是UTF-16到UTF -8,这我想要的完全相反.所以这是第一个问题:

1)如何使用codecvt thingamajigs将我的UTF-8字符串转换为UTF-16进行WinAPI调用,UTF-16结果返回UTF-8?

另一个问题:我也在瞄准Linux.在Linux上,对许多不同的语言环境有很好的支持 - 我不希望有任何不同.希望每个人都在他们的Linux机器上使用UTF-8,但没有严格的保证.所以我认为扩展上面特定于Windows的行为并始终执行UTF-8到系统区域设置编码是一个好主意.除了我没有看到在C++ 11的<locale>库中有任何方法来获得当前的系统编码!默认的std :: locale构造函数使用自己定义的语言环境,如果不这样做,它将返回经典的"C"语言环境.并且没有其他我知道的吸气剂.所以这是第二个问题:

2)如何检测当前系统区域设置?什么东西<locale>?也许一些标准的C库函数,或者(在这种情况下可移动性较差)POSIX API中的东西?

leg*_*ize -1

标准库中这些设施的设计假设多字节字符编码(如UTF-8)仅用于外部存储(即磁盘上文件中的字节序列)并且内存中的所有字符大小都是统一的。这样一来,诸如此类的事物std::basic_string<T>::operator[]就可以按照与标准所施加的性能约束一致的方式运行。因此,虽然您可以使用以 UTF-8 或其他 MBCS(如日语)编码的文件,但内存中的字符串应该是charchar16_t或。char32_twchar_t

这就是为什么您在标准库中找不到与您想要执行的操作匹配的原因,因为内存中的字符串不打算以 UTF-8 存储。这也类似于其他语言,例如 Java,其中磁盘上的数据被解释为字节流,并将它们转换为字符串,您需要告诉某些组件字节流的预期字符编码。某些操作系统可能会将 UTF-8 字符串填充到 中argv[],但这是非标准的。WinMain这就是Windows 上启用 Unicode 的入口点提供NUL终止指针wchar_t而不是char*指向 UTF-8 编码字符串的原因。

IBM 的International Components for Unicode库提供了一整套组件,这些组件是对 C++ 标准库的补充,并且旨在与 C++ 标准库配合使用。我会看看他们的代码转换工具。虽然该标准定义了<locale>用于代码转换的工具,但它不保证存在从 UTF-8 映射到 、 或 的代码char16_t转换char32_t工具wchar_t。如果存在这种情况,您只能根据实现的详细信息来获取它。ICU 库为任何 C++ 实现可移植地提供此功能。它得到了很好的支持和使用,并且不太可能在将 UTF-8 字符串解码为适当的宽于char字符串时出现错误。

Konrad 在评论中提到了 UTF-8 Anywhere 宣言。这是一本有趣的读物,他们将您引向Boost.Nowide库(尚未正式成为 boost 的一部分)以获得您上面引用的问题的解决方案。

请注意,我的回答只是对现有 C++ 标准库类工作方式的描述std::basic_string<T>。这并不是针对 UTF-8、Unicode 或其他任何内容的建议。引用的宣言同意我的观点,即这些东西根本无法以这种方式工作,如果您想在任何地方使用 UTF-8,那么您需要其他东西。

  • “内存中的字符串不适合以 UTF-8 格式存储。”——不。你错了。[UTF-8 Anywhere 宣言](http://www.utf8everywhere.org/) 不同意您的观点,并且该文档被许多开发人员视为非常好的总结。总之,“std::string”是 UTF-8 的一个不错的容器,并且标准库无论如何都没有提供足够的工具来使用 Unicode,无论底层字符类型如何。 (3认同)
  • 标准库在处理文本方面存在缺陷,从其设计角度争论是没有意义的。`std::string` 是字节存储,而不是文本存储。但完全允许使用 std::string 作为 UTF-8 编码文本的透明存储,只要您不以与编码无关的方式对其进行操作即可。为此,您需要一个库(例如 ICU 或 [Ogonek](http://flamingdangerzone.com/ogonek/),它具有更好的 C++ 界面,但仍然不完整)。 (2认同)