【问题标题】:QString in Persian波斯语中的 QString
【发布时间】:2019-01-31 17:43:41
【问题描述】:

我给出了一个需要支持波斯语的 Qt 项目。数据是从服务器发送的,使用第一行,我得到一个 QByteArray 并使用第二行将其转换为 QString:

    QByteArray readData = socket->readAll();
    QString DataAsString = QTextCodec::codecForUtfText(readData)->toUnicode(readData);

当发送的数据是英文时,一切都很好,但是当它是波斯语时,而不是

سلام

我明白了

سÙ\u0084اÙ\u0085

我提到了这个过程,所以人们不会建议制作使用 .tr 的多语言应用程序的方法。一切都与文本和解码有关,而不是那些翻译方法。我的操作系统是 Windows 8.1(你需要知道的情况)。

当服务器发送 سلام 时,我得到这个十六进制值

0008d8b3d984d8a7d985

顺便说一下,服务器在开头发送了两个额外的字节,原因我不知道。所以我把它切断了:

DataAsString.remove(0,2);

在它被转换为 QString 之后,十六进制值在乞求时有一些额外的。

【问题讨论】:

  • 改用QString DataAsString = QString::fromUtf8(readData)codecForUtfText 查找字节顺序标记,但没有找到并假定为 Latin-1 编码。
  • @IgorTandetnik 感谢您的回复。我尝试了您的代码,它给了我“”。您自己尝试了吗?请告诉我。
  • 能否将readData 的值发布为十六进制值?
  • @scopchanov 基于我的浏览器和 Notepad++ 支持 UTF-8(或其他兼容的 Unicode 编码)这一事实,我已将文本“سلام”放入 Notepad++。 hexdump 产生“d8 b3 d9 84 d8 a7 d9 85”。 (我也想复制相应的 Latin-1 输出,但 Notepad++ 在我完成之前就死了。)
  • 请使用QByteArray::toHex() 将您的dataRead 转换为十六进制转储,打印并将结果添加到您的问题中(使用edit)。如果它与我在 Notepad++ 中得到的相同,那么您的编码是 UTF-8。如果是不同的东西,也许有人可以从数字中猜到。

标签: c++ qt text decoding


【解决方案1】:

我非常好奇地等待回复并自己玩弄了一下:

我复制了文本 سلام(英文:“Hello”)并将其粘贴到 Nodepad++(在我的例子中使用 UTF-8 编码)。然后我切换到 View as Hex 并得到:

右侧的 ASCII 转储看起来与 OP 意外得到的有点相似。这让我相信readData 中的字节是用 UTF-8 编码的。因此,我采用了暴露的十六进制数字并制作了一些示例代码:

testQPersian.cc:

#include <QtWidgets>

int main(int argc, char **argv)
{
  QByteArray readData = "\xd8\xb3\xd9\x84\xd8\xa7\xd9\x85";
  QString textLatin1 = QString::fromLatin1(readData);
  QString textUtf8 = QString::fromUtf8(readData);
  QApplication app(argc, argv);
  QWidget qWin;
  QGridLayout qGrid;
  qGrid.addWidget(new QLabel("Latin-1:"), 0, 0);
  qGrid.addWidget(new QLabel(textLatin1), 0, 1);
  qGrid.addWidget(new QLabel("UTF-8:"), 1, 0);
  qGrid.addWidget(new QLabel(textUtf8), 1, 1);
  qWin.setLayout(&qGrid);
  qWin.show();
  return app.exec();
}

testQPersian.pro:

SOURCES = testQPersian.cc

QT += widgets

在 Windows 10 上的 cygwin 中编译和测试:

$ qmake-qt5 testQPersian.pro

$ make

$ ./testQPersian

同样,Latin-1 的输出看起来有点类似于 OP 得到的以及 Notepad++ 公开的输出。

UTF-8 的输出提供了预期的文本(正如预期的那样,因为我提供了正确的 UTF-8 编码作为输入)。

可能,ASCII/Latin-1 输出的变化有点令人困惑。 – 存在多个字符字节编码,它们在下半部分(0 ... 127)共享 ASCII,但在上半部分(128 ... 255)具有不同的字节含义。 (看看ISO/IEC 8859 了解我的意思。在Unicode 作为本地化问题的最终解决方案流行之前,这些已经作为本地化引入。)

波斯字符肯定有超过 127 的所有 Unicode 代码点。(Unicode 也共享前 128 个代码点的 ASCII。)这些代码点在UTF-8 中编码为多个字节的序列,其中每个字节都有 MSB(最多有效位 – 位 7) 设置。因此,如果这些字节(意外地)使用任何 ISO8859 编码进行解释,则上半部分变得相关。因此,根据当前使用的 ISO8859 编码,这可能会产生不同的字形。


一些继续:

OP 发送了以下快照:

所以,它似乎不是

d8 b3 d9 84 d8 a7 d9 85

他得到了

00 08 d8 b3 d9 84 d8 a7 d9 85

一种可能的解释:

服务器首先发送一个 16 位长度的 00 08 - 解释为 Big-Endian 16 位整数:8,然后是 UTF-8 编码的 8 个字节(即看起来和我上面玩的一模一样)。 (AFAIK,如果发送方和接收方本身具有不同的字节序,则将 Big-Endian 用于二进制网络协议以防止字节序问题并不罕见。)进一步阅读例如这里:htons(3) - Linux man page

在 i386 上,主机字节顺序是最低有效字节在前,而在 Internet 上使用的网络字节顺序是最高有效字节在前。


OP声称使用此协议DataOutput – writeUTF

将两个字节的长度信息写入输出流,然后是字符串 s 中每个字符的修改后的 UTF-8 表示。如果 s 为 null,则抛出 NullPointerException。字符串 s 中的每个字符都根据字符的值转换为一组一个、两个或三个字节。

因此,解码可能如下所示:

QByteArray readData("\x00\x08\xd8\xb3\xd9\x84\xd8\xa7\xd9\x85", 10);
//QByteArray readData = socket->readAll();
unsigned length
  = ((uint8_t)readData[0] <<  8) + (uint8_t)readData[1];
QString text = QString::fromUtf8(dataRead.data() + 2, length);
  1. 前两个字节从readData 中提取并组合成length(解码big-endian 16 位整数)。

  2. dataRead 的其余部分转换为 QString,提供先前提取的 length。因此,readData 的前 2 个长度字节被跳过。

【讨论】:

  • 我使用了你的代码,它给了我空的“”,但在 UI 和控制台上。 QString textLatin1 = QString::fromLatin1(readData); QString textUtf8 = QString::fromUtf8(readData); qDebug() &lt;&lt; textUtf8 &lt;&lt; "\n" &lt;&lt; textLatin1; emit(MessageSent("Clint said: " + textLatin1 + "\n" + textUtf8)); @ 和换行不起作用。
  • @stevemoretz 我将它作为 GUI 应用程序(使用QLabel)制作,我确信我的 Windows 10 控制台无法打印 UTF-8。 (我为此苦苦挣扎了很多次。即使明确地将其设置为 UTF-8 也只会打印出无意义的东西。)相反,GUI 对 Unicode 有很好的支持。 (MS 内部使用 UTF-16。)如果您想在 Windows 控制台上打印,您必须设置一个包含所需字形的代码页并分别本地化 QString。如果你在 Linux 上,它可能会好得多。即使在cygwin中,xterm也支持UTF-8,而且UTF-8的控制台输出也很好。
  • @stevemoretz 你能用我的代码原样重现结果吗?
  • 我在windows上。只是为了演示而使用了qDebug,这是一个GUI应用程序,在我放的两张图片上,但是consol和GUI结果这是我在这里使用的QMessageBox。但是我仍然无法得到你得到的结果。
【解决方案2】:

您需要像这样使用 utf8 发送数据

    mysocket->write(message.toUtf8());

并像这样接收并转换为 utf8:

    QByteArray Data = mysocket->readAll();
    QString DataAsString = QString::fromUtf8(Data);

您的数据将被发送而不会变得无法识别

【讨论】:

  • 你好 Arash 不,问题是服务器在 Android 上,所以你不能使用这个答案。谢谢你的尝试。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多