将UTF-8编码的文件读取到std :: U32String中,而无需中间缓冲



在Unicode和C 工作很长时间以来,我认为这将是一件简单的事情,尤其是使用新的C 11 std::codecvt_utf8 Facet。尽管事实证明这是一项困难的任务。我想要的是将UTF-8中编码的文件读取到U32String中(将其从UTF-8转换为UTF-32)。当然,我可以将整个内容加载到缓冲区中,并使用std::wstring_convert转换。但这在加载文件时会加倍内存足迹。因此,我尝试使用std :: wifstream,并用像这样的UTF-8方面填充语言环境:

std::wifstream stream(fileName, std::ios::binary);
stream.imbue(std::locale(stream.getloc(), new std::codecvt_utf8<char32_t, 0x10ffff, std::consume_header>));
std::u32string data;
for (char32_t c; stream >> c; )
  data += c;

看起来直接实现。它只不编译。WifStream的元素类型是wchar_t,因此您只能在循环中使用wchar_t,例如:

std::u32string data;
for (wchar_t c; stream >> c; )
  data += c;

(至少使用Clang,VC 也接受Char32_t,但这并没有改变任何东西)。解决了其他几个问题之后,仍然存在:

  • 在Visual C WCHAR_T中只有16位(没有UTF-32,我们在这里不考虑替代对)。
  • 使用 char32_t进行方面基本上禁用转换。流上的迭代返回原始的UTF-8内容,包括Clang和VC 。
  • 也将wchar_t用于该方面使其在Clang中起作用,但在VC 中不使用,因为在Clang wchar_t中是32位宽,而(如前所述)在VC 中仅16位。

那么,这里的正确方法是什么?锁定到facet中的WCHAR_T时,我什至无法使用其他数据类型。我还尝试定义basic_ifstream<char32_t>,但这需要其他类型,因此我没有进一步遵循这条路。

似乎没有办法在流中使用一个方面,所以我选择了一个中间缓冲液,这也是一个非常优雅的解决方案,只有它会加倍(或多或少))加载内容所需的内存。在二进制模式下使用字节(文件)流来调用以下方式:

void load(std::istream &stream)
{
  static std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> utfConverter;
  std::string s((std::istreambuf_iterator<char>(stream)), std::istreambuf_iterator<char>());
  _data = utfConverter.from_bytes(s);
}

最新更新