c++ - 使用标准 C++ wifstream 读取 UTF-8 文本并转换为 UTF-16

标签 c++ c++11 utf-8 visual-studio-2013 iostream

我想从使用 UTF-8 编码的文件中读取一些文本,然后使用 std::wifstream 将其转换为 UTF-16,如下所示:

//
// Read UTF-8 text and convert to UTF-16
//
std::wifstream src;
src.imbue(std::locale("???"));          // UTF-8 ???
src.open("some_text_file_using_utf8");
std::wstring line;                      // UTF-16 string
while (std::getline(src, line))
{
    ... do something processing the UTF-16 string ...
}

是否有用于 UTF-8 转换的标准语言环境名称?
是否可以使用 std::locale 实现该目标?

我使用的是 Visual Studio 2013。


注意:

我知道 I/O 流往往很慢,可以使用 Win32 内存映射文件来加快读取速度,并使用 MultiByteToWideChar() Win32 API 进行转换等。
但对于这种特殊情况,我想要一个仅使用标准 C++ 及其标准库没有 Boost 的解决方案。

如果 C++ 标准库不能做到这一点,第二个 选项是使用 Boost;在这种情况下,我应该使用哪个 Boost 库?

最佳答案

这可以在带有 Visual Studio 的 Windows 上运行,我想可以追溯到 VS2010

#include <locale>  // consume_header, locale
#include <codecvt> // codecvt_utf8_utf16

src.imbue(std::locale(
    src.getloc(),
    new std::codecvt_utf8_utf16<wchar_t, 0x10FFFF, std::consume_header>));

由于 Windows 使用 16 位 wchar_t并且还普遍使用 UTF-16 作为宽字符编码,这在那种环境下效果很好。 (因为我假设是 Windows 环境,所以我的示例包含 consume_header 来处理 Windows 向 UTF-8 数据添加 header 的约定)。

在其他平台上wchar_t通常是 32 位的,虽然您可以将 UTF-16 代码单元值存储在这样的 32 位代码单元中,但不会编写任何其他期望这样的东西。在具有 32 位 wchar_t 的平台上你可能更喜欢使用 std::codecvt_utf8<wchar_t>生成 UTF-32 宽字符串。


理想情况下,为了可移植性,您需要一个知道如何从 UTF-8 转换为语言环境的 wchar_t 的 codecvt 方面。编码或宽执行编码。然而,这样做的问题是,不需要任何宽编码来支持 UTF-8 中可表示的整个字符范围。底线是 wchar_t对于指定的可移植代码不是特别有用。

但是,如果您根据 wchar_t 的大小坚持使用 UTF-16 或 UTF-32 的平台,那么一个技巧可能会有用。是:

template <int N> struct get_codecvt_utf8_wchar_impl;
template <> struct get_codecvt_utf8_wchar_impl<16> {
  using type = std::codecvt_utf8_utf16<wchar_t>;
};
template <> struct get_codecvt_utf8_wchar_impl<32> {
  using type = std::codecvt_utf8<wchar_t>;
};

using codecvt_utf8_wchar = get_codecvt_utf8_wchar_impl<
    sizeof(wchar_t) * CHAR_BIT>::type;

src.imbue(std::locale(src.getloc(), new codecvt_utf8_wchar));

您还可以使用 char16_tchar32_t ,这将适用于可移植代码,但是该标准缺少一些位来使 iostream 可用于这些字符类型,而且实现不完全支持指定的内容。

我认为 VS 仍然实现了 char16_tchar32_t作为 typedef,因此使用它们的模板特化不起作用(即使如果您查看 header ,特化确实存在,它们只是 ifdef'd out,因为编译器无法处理它们). libstdc++ 还没有实现模板特化,即使它支持 char16_tchar32_t作为真实类型。我所知道的最完整的实现是带有合适编译器(gcc 或 clang)的 libc++,但即便如此仍然缺少 <cuchar>标题。

由于实现支持有限,因此除了将它们用作跨平台用户代码中的一致表示之外,可移植代码无法对它们做很多事情(尽管即使单独使用也很有用)。

关于c++ - 使用标准 C++ wifstream 读取 UTF-8 文本并转换为 UTF-16,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21636374/

相关文章:

C++ 类 + 对象和用户交互

c++ - 为什么运算符不能放在括号中?

python - 从文本文件读取时的 Unicode 编码

java - 将任何字符串转换为 UTF-8 格式

c++ - 存储成员指针与成员值

c++ - 如何使用 "class name1::name2::name3"表示法在 C++ 中定义类

具有 Fluent 界面的 C++ Builder 模式

c++ - C++中具有相同名称但成员不同的结构

c++ - 类的只读成员变量

http - 通过 postman 而不是通过java代码在elasticsearch中查询