Qt UTF-8文件到std :: string添加额外的字符

时间:2019-07-11 13:21:05

标签: c++ string qt utf-8

我有一个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字符。它应该能够重现最初读取的文件,还是我完全丢失了什么?

2 个答案:

答案 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

现在,关于您在调试器中看到的内容:

  1. 您已经在注释之一中指出“ QString的字符串中仅包含0xC2 0xB2(正确)。”这仅部分正确:QString在内部使用UTF-16LE,这意味着其内部字符数组包含两个16位值:0x00C2 0x00B2。实际上,当每个字符都编码为UTF-16时,它们映射到字符²,这证明QString是基于文件输入正确构建的。但是,您的调试器似乎足够聪明,可以知道构成QString的字节是用UTF-16编码的,因此可以正确呈现字符。
  2. 您还说过,调试器将从std::string返回的QString::toStdString的内容显示为²。假设您的调试器在没有明确说明编码的情况下使用可怕的“ ANSI代码页”将字节解析为字符,并且您使用的是英语Windows,而Windows 1252作为其默认旧版代码页,则一切都准备就绪:std::string实际上包含字节C3 82 C2 B2,它们映射到delivered a talk about character encodings中的字符²

无耻的自拔:我{{3}}在去年的一次会议上。也许观看它可以帮助您更好地了解其中一些问题。

最后一件事: ANSI不是编码。根据Windows的区域设置,它可能意味着许多不同的编码。