在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 中不使用,因为在Clangwchar_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);
}