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

Mr.*_*C64 5 c++ iostream utf-8 c++11 visual-studio-2013

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

//
// 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 ...
}
Run Code Online (Sandbox Code Playgroud)

是否有UTF-8转换的标准区域设置名称?
是否有可能实现这一目标std::locale

我正在使用Visual Studio 2013.


注意:

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

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

bam*_*s53 6

这适用于使用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>));
Run Code Online (Sandbox Code Playgroud)

由于Windows使用16位wchar_t并且通常使用UTF-16作为宽字符编码,因此在该环境中工作得很好.(因为我假设一个Windows环境,我的例子包括consume_header处理Windows向UTF-8数据添加标题的惯例).

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


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

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

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));
Run Code Online (Sandbox Code Playgroud)

您也可以使用char16_tchar32_t,它们可以使用自己的可移植代码,但是标准缺少一些位以使iostream可以与这些字符类型一起使用,并且实现也不完全支持指定的内容.

VS我认为仍然实现char16_tchar32_t作为typedef,因此使用它们的模板专业化不起作用(即使专业化确实存在,如果你查看标题,它们只是因为编译器无法处理它们而被解决) .libstdc ++尚未实现模板特化,即使它支持char16_tchar32_t作为真实类型.我所知道的最完整的实现是带有合适的编译器(gcc或clang)的libc ++,但即使这样仍然缺少<cuchar>标题.

由于实现支持是有限的,除了使用它们作为跨平台的用户代码中的一致表示(尽管这甚至单独使用)之外,这种方式可以防止可移植代码对这些做很多事情.