我有一个UTF-8编码的文本文件,其中包含²,³,Ç和ó等字符。当我使用以下内容读取文件时,文件似乎已正确读取(至少根据我在查看contents
变量的内容时在Visual Studio编辑器中看到的内容)
QFile file( filePath );
if ( !file.open( QFile::ReadOnly | QFile::Text ) ) {
return;
}
QString contents;
QTextStream stream( &file );
contents.append( stream.readAll() );
file.close();
但是,一旦内容转换为std::string
,就会添加其他字符。例如,²
转换为²
时应为²。对于每个非ANSI字符,似乎都会发生这种情况,会添加额外的Â
,这当然意味着在保存新文件时,输出文件中的字符不正确。
我当然只是尝试过toStdString()
,我也尝试过toUtf8
,甚至尝试过使用QTextCodec
,但是每个都无法给出正确的值。
我不明白为什么从UTF-8文件转到QString,然后到std :: string会丢失UTF-8字符。它应该能够重现最初读取的文件,还是我完全丢失了什么?
答案 0 :(得分:2)
如丹尼尔·卡米尔·科扎尔(Daniel Kamil Kozar)在回答中所提到的,QTextStream
无法读取编码,因此实际上无法正确读取文件。 QTextStream
必须在读取文件之前设置其编解码器,以便正确解析字符。在下面的代码中添加了注释,以显示所需的额外文件。
QFile file( filePath );
if ( !file.open( QFile::ReadOnly | QFile::Text ) ) {
return;
}
QString contents;
QTextStream stream( &file );
stream.setCodec( QTextCodec::codecForName( "UTF-8" ) ); // This is required.
contents.append( stream.readAll() );
file.close();
答案 1 :(得分:0)
您看到的实际上是预期的行为。
当字符串²
编码为UTF-8时,由字节C3 82 C2 B2
组成。假设QTextStream
实际上能正确识别UTF-8(judging from the documentation并不那么明显,returns a UTF-8 encoded variant,它仅在存在BOM时提及字符编码检测,而您对输入内容一无所知具有BOM表的文件),我们可以假设QString
返回的QTextStream::readAll
实际上包含字符串²
。
QString::toStdString()
表示的字符串的 QString
Windows-1252,因此返回值应包含与输入文件相同的字节,即C3 82 C2 B2
。
现在,关于您在调试器中看到的内容:
0xC2 0xB2
(正确)。”这仅部分正确:QString在内部使用UTF-16LE,这意味着其内部字符数组包含两个16位值:0x00C2 0x00B2
。实际上,当每个字符都编码为UTF-16时,它们映射到字符Â
和²
,这证明QString
是基于文件输入正确构建的。但是,您的调试器似乎足够聪明,可以知道构成QString
的字节是用UTF-16编码的,因此可以正确呈现字符。std::string
返回的QString::toStdString
的内容显示为²
。假设您的调试器在没有明确说明编码的情况下使用可怕的“ ANSI代码页”将字节解析为字符,并且您使用的是英语Windows,而Windows 1252作为其默认旧版代码页,则一切都准备就绪:std::string
实际上包含字节C3 82 C2 B2
,它们映射到delivered a talk about character encodings中的字符²
。无耻的自拔:我{{3}}在去年的一次会议上。也许观看它可以帮助您更好地了解其中一些问题。
最后一件事: ANSI不是编码。根据Windows的区域设置,它可能意味着许多不同的编码。