Qt 5编码问题(UTF-8,Windows-1250,Windows-1251)

3

我的所有源文件都经过UTF-8转换。

我打开的所有文件都是UTF-8编码的。

我的应用程序打开了一个UTF-8编码的文件,其中包含了三种语言(英语、波兰语和俄语)的翻译文本,并将数据保存到一个文件中,分为三个单独的编码块:Windows-1250(英语)、Windows-1250(波兰语)和Windows-1251(俄语) - 是的,我在一个文件内混合使用不同的编码类型,这个文件由第三方设备使用,该设备知道如何处理它。

我有一个测试程序,在Qt4下完美运行,但当我移植到Qt5后,它停止工作了(文本存储为“???”):

  • test_encoding.cpp

    test_encoding::test_encoding(QWidget *parent) : QMainWindow(parent)
    {
      ui.setupUi(this);
    
      QString d;
      QFile f(QDir::currentPath() + "/input.txt");
      if( f.open( QIODevice::ReadOnly | QIODevice::Text ) )
      {
        d = f.readAll();
        f.close();
      }
    
      QFile ff(QDir::currentPath() + "/output.txt");
      if( ff.open( QIODevice::WriteOnly | QIODevice::Text ) )
      {
        QTextStream t(&ff);
        auto cutf8 = QTextCodec::codecForName("UTF-8");
        auto cw50 = QTextCodec::codecForName("windows-1250");
        auto cw51 = QTextCodec::codecForName("windows-1251");
    
            // ____Block 1
        t.setCodec(cutf8);
        t << d << "\r\n";
        t << cutf8->fromUnicode(d) << "\r\n";
        t.flush();
    
            // ____Block 2
        t.setCodec(cw50);
        t << d << "\r\n";
        t << cw50->fromUnicode(d) << "\r\n";
        t.flush();
    
            // ____Block 3
        t.setCodec(cw51);
        t << d << "\r\n";
        t << cw51->fromUnicode(d) << "\r\n";
        t.flush();
      }
      ff.close();
    
      QCoreApplication::quit();
    }
    
  • input.txt (UTF-8 without BOM)

未登录用户

Not logged-in user

未注册用户

  • output.txt (多代码页块)

____块1:

未登录用户

Not logged-in user

未注册用户

未登录用户

Not logged-in user

未注册用户

____块2:

未登录用户

Not logged-in user

无法识别的字符集

未登录用户

Not logged-in user

无法识别的字符集

____块3:

未登录用户

Not logged-in user

无法识别的字符集

未登录用户

Not logged-in user

无法识别的字符集

看起来只能将文本保存为UTF-8,这对我来说不太合适 - 我需要使用Windows-1251和Windows-1250代码页。

在Qt5中是否可以将UTF-8转换为其他代码页?


我看到你在一个文件中使用了多个代码页,说实话,这是荒谬的。如果你分别编写这三个文件会发生什么呢? - Karol S
这不是无意义的。将文本转换的代码是更大编译器的一部分,该编译器为各种微控制器和DSP准备代码。将所有文本放在一个文件中非常方便,实际上这是一个C(* .c)表声明文件 - 请查看链接http://pastebin.com/ck8bpifw。 它可以支持任意数量的语言 - 如果我有多个文件,那么我必须生成多个ifdef并更正编译器。发生了什么?如果我将其保存到单独的文件中,则有效 - 但在我之前的QT4中已经起作用:1)setCodec()2)flush()3)setCodec ......等! - killdaclick
最终输出来自哪里?如果是从编辑器复制粘贴的,那么该编辑器无法处理多个编码。我建议您使用十六进制编辑器检查文件。 - Karol S
我把完全使用UTF-8编码的错误代码从编辑器中粘贴了出来。正确的代码(适用于Windows-1250代码页)在这里:http://pastebin.com/rgd7Pfj7,源文件在这里:http://sendfile.pl/download.php?id=134515。我进行了一些测试,似乎由于某种原因QT5无法使用setCodec()动态切换代码页。在QT4中一切正常。如果我销毁QTextStream对象并为相同的QIODevice创建一个新的对象并设置代码页,它就像在QT4中一样工作:http://pastebin.com/EpWV2geT。 - killdaclick
我检查了QT5的源代码,发现当第一个QTextStream::flush()被触发时(无论是用户还是系统强制),QIcuCodec::convertToUnicode会被执行并进行转换初始化。之后程序会检查转换器是否已经初始化,如果已经初始化,则不会加载新的编解码器 - 第5行http://pastebin.com/2dEcCyET 当我通过调试器强制让可执行文件跳转到第7行(即使它之前已经初始化),那么转换就像在QT4中一样 - 即时设置编解码器! - killdaclick
1个回答

5

Qt 5存在一个Bug,我已向Qt报告:https://bugreports.qt.io/browse/QTBUG-42498

目前的解决方法是每次想要更改代码页时创建一个新的QTextStream对象 - 在执行QTextStream::flush()之后,使用QTextStream::setCodec()更改代码页是不可能的 - 请查看上面链接中的错误描述。 问题出现在QIcuCodec::getConverter()源代码的第5行 - http://pastebin.com/2dEcCyET

因此,在Qt 5中无法正常工作(而在Qt 4.8.4中可以)的代码如下:

QFile f;
QTextStream ts(&f);
ts.setCodec("Windows-1250");
ts << englishTranslationBlock();
ts << polishTranslationBlock();
ts.flush();
ts.setCodec("Windows-1251");
ts << russianTranslationBlock();
ts.flush();
f.close();

为了解决报告的错误,代码必须创建一个新的QTextStream以允许编码更改。代码写成这样将可以工作:
QFile f;
QTextStream* ts = new QTextStream(&f);
ts->setCodec("Windows-1250");
ts << englishTranslationBlock();
ts << polishTranslationBlock();
ts->flush();
delete ts;
ts = new QTextStream(&f);
ts->setCodec("Windows-1251");
ts << russianTranslationBlock();
ts->flush();
f.close();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接