我有一个文件,行结尾是windows样式\r\n
;它以USC-2小端编码。
说这是我的文件fruit.txt
(USC-2 little endian):
所以我在std::wifstream
中打开它并尝试解析内容:
// open the file
std::wifstream file("fruit.txt");
if( ! file.is_open() ) throw std::runtime_error(std::strerror(errno));
// create container for the lines
std::forward_list<std::string> lines;
// Add each line to the container
std::wstring line;
while(std::getline(file,line)) lines.emplace_front(wstring_to_string(line));
如果我尝试打印到cout ......
// Printing to cout
for( auto it = lines.cbegin(); it != lines.cend(); ++it )
std::cout << *it << std::endl;
......这就是它输出的内容:
Cherry
Banana
ÿþApple
更糟糕的是,如果我在Notepad ++中打开它,它就是它的样子
我可以通过强制将编码转换回USC-2来解决这个问题,从而产生这样的结果:
我的wstring_to_string
函数定义如下:
std::string wstring_to_string( const std::wstring& wstr ) {
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> convert;
return convert.to_bytes(wstr);
}
世界上到底发生了什么?如何获得正常的UTF-8字符串?我也试过这种方法:How to read utf-16 file into utf-8 std::string line by line,但首先导致std::wifstream
结果没有输出。有人可以帮助指导我将USC-2 LE数据转换为可读的UTF-8数据吗?
编辑我认为可能存在由MSYS2提供的mingw64 / mingw-w64-x86_64-gcc 6.3.0-2的错误。我已经尝试了所有人的建议,并将区域设置添加到流中只是根本没有输出。我知道只提供了两种本地语言环境,&#34; C&#34;和&#34; POSIX&#34;。我打算尝试Visual Studio,但没有足够的互联网速度进行4GB下载。我使用了像@Andrei R.建议的ICU并且它工作得很好。
我本来喜欢使用标准库,但我对此感到满意。如果您需要此解决方案,请查看我的代码:https://pastebin.com/qudy7yva
答案 0 :(得分:1)
代码本身很好。
真正的问题是你的输入文件开头是无效的UTF-16LE(你使用std::codecvt_utf8_utf16
需要UTF-16,而不是UCS-2)。这在Notepad ++屏幕截图中清晰显示。
另外,文件数据看起来像一个带有BOM的UTF-16LE文件(ÿþ
是UTF-16LE BOM,当被视为8位ANSI时)被原样附加到没有BOM的UCS-2BE(或UTF-16BE)文件的结尾。
您需要修复输入文件,以便整个文件从头到尾都是有效的UTF-16LE(前面有或没有BOM,不在中间)。
然后您已经拥有的代码将起作用。
答案 1 :(得分:0)
转换为unicode /从unicode转换通常不是那么简单。看看ICU库,我相信这是迄今为止用于c / c ++的最完整的编码转换库。
还有与WideCharToMultibyte (Win)或iconv (Linux)相关的平台相关方式。或者,使用Qt,您可以使用QString::fromUtf16
。可能你必须自己反转字节序。
答案 2 :(得分:0)
对于您的情况,主要问题是您使wifstream
以错误的方式读取文件。如果你在wstring_to_string中打印wstr的大小,你会发现它不是你所期望的。
https://stackoverflow.com/a/19698449/4005852
设置正确的区域设置将解决此问题。
std::string wstring_to_string( const std::wstring& wstr ) {
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> convert;
return convert.to_bytes(wstr);
}
int main()
{
// open the file
std::wifstream file("fruit.txt", std::ios::binary);
file.imbue(std::locale(file.getloc(),
new std::codecvt_utf16<wchar_t, 0x10ffff, std::little_endian>));
if( ! file.is_open() ) throw std::runtime_error(std::strerror(errno));
// create container for the lines
std::forward_list<std::string> lines;
// Add each line to the container
std::wstring line;
file.get(); // remove BOM
while(std::getline(file,line)) lines.emplace_front(wstring_to_string(line));
// Printing to cout
for( auto it = lines.cbegin(); it != lines.cend(); ++it )
std::cout << *it << std::endl;
return 0;
}