QString по-персидски - PullRequest
       1

QString по-персидски

0 голосов
/ 25 августа 2018

Я дал проект 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, так что в начале шестнадцатеричное значение имеет некоторые дополнительные значения.

Ответы [ 2 ]

0 голосов
/ 27 ноября 2018

вам нужно отправить данные с помощью utf8 следующим образом

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

, а также получить и преобразовать в utf8 следующим образом:

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

ваши данные будут отправлены без возможности их распознавания

0 голосов
/ 26 августа 2018

Мне было очень любопытно дождаться ответа, и я немного поиграл:

Я скопировал текст سلام (на английском языке: "Hello") и вставил его в Nodepad ++ (который использовал UTF).-8 кодировка в моем случае).Затем я переключился на View as Hex и получил:

snapshot of Notepad++ - hex dump of

Дамп 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

Скомпилировано ипроверено в cygwin в Windows 10:

$ qmake-qt5 testQPersian.pro

$ make

$ ./testQPersian

snapshot of testQPersian

Снова вывод в виде латиницы1 выглядит немного похожим на то, что получил OP, а также на то, что показал Notepad ++.

Вывод в виде UTF-8 обеспечивает ожидаемый текст (как и ожидалось, потому что я предоставил правильную кодировку UTF-8 в качестве ввода).

Может быть, немного странно, что выходные данные ASCII / Latin-1 различаются.- Существует несколько кодировок байтов символов, которые разделяют ASCII в нижней половине (0 ... 127), но имеют различные значения байтов в верхней половине (128 ... 255).(Посмотрите на ISO / IEC 8859 , чтобы понять, что я имею в виду. Они были введены в качестве локализаций до того, как Unicode стал популярным как окончательное решение проблемы локализации.)

Персидские символы, безусловно, имеют все кодовые точки Unicode, кроме 127. (Unicode разделяет ASCII и для первых 128 кодовых точек.) Такие кодовые точки кодируются в UTF-8 как последовательности из нескольких байтов, где каждый байтимеет MSB (самый старший бит - бит 7).Следовательно, если эти байты (случайно) интерпретируются с использованием любой кодировки ISO8859, тогда верхняя половина становится релевантной.Таким образом, в зависимости от используемой в настоящее время кодировки ISO8859 это может привести к различным символам.


Некоторое продолжение:

OP отправил следующий снимок:

enter image description here

Итак, кажется, вместо

d8 b3 d9 84 d8 a7 d9 85

он получил

00 08 d8 b3 d9 84 d8 a7 d9 85

AВозможная интерпретация:

Сервер отправляет сначала 16-битную длину 00 08 - интерпретируется как Big-Endian 16-битное целое число: 8 , затем 8 байтов, закодированных в UTF-8 (которые выглядят точно так же, как тот, что я получил, играя выше).(AFAIK, нередко использовать Big-Endian для двоичных сетевых протоколов, чтобы предотвратить проблемы с порядком байтов, если отправитель и получатель имеют изначально разные порядковые номера байтов.) Дополнительная информация, например, здесь: htons (3) - страница руководства Linux

На i386 порядок байтов хоста - сначала Наименьший значащий байт, тогда как порядок байтов в сети, используемый в Интернете, - наибольший значащий байт вначале.


OP утверждает, что этот протокол используется DataOutput - writeUTF :

Записывает два байта информации о длине в выходной поток, за которым следует измененное представление 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 (декодирование 16-разрядного целого числа с прямым порядком байтов).

  2. Остальная часть dataRead преобразуется в QString, предоставляя ранее извлеченную length.Таким образом, первые 2 байта длины readData пропускаются.

...