Как эффективно преобразовать только один следующий символ из байтового массива UTF-8?
У меня есть этот код, который работает:
QString qs = QString::fromUtf8(bp,ut).at(0);
QChar c(qs[0]);
куда bp
это QByteArray::const_pointer
, а также ut
максимальная ожидаемая длина кодированной точки Unicode в кодировке UTF-8. Затем я беру первый QChar c
от QString qs
, Похоже, что должен быть более эффективный способ получить только следующее QChar
из байтового массива UTF-8 без необходимости преобразования произвольного количества QByteArray
в QString
а потом получаю только первое QChar
,
РЕДАКТИРОВАТЬ Из комментариев ниже, ясно, что никто еще не понимает мой вопрос. Итак, я начну с некоторых основ. UTF-8 и UTF-16 - это две разные кодировки мирового стандарта Unicode. Наиболее распространенной и рекомендуемой кодировкой Unicode для передачи через Интернет и текстовыми файлами Unicode является UTF-8, в результате чего каждая кодовая точка Unicode использует от 1 до 4 байтов в кодировке UTF-8. UTF-16, с другой стороны, более удобен для обработки символов внутри программы. Поэтому подавляющее большинство программного обеспечения постоянно выполняет преобразование между этими двумя кодировками. QChar - это более удобное кодирование UTF-16 для всех кодовых точек Unicode от 0x00 до 0xffff, которое охватывает большинство языков и символов, определенных на данный момент и широко используемых. Суррогатные пары используются для более высоких значений кодовой точки Unicode. В настоящее время кажется, что суррогатные пары имеют ограниченную поддержку и не представляют интереса для меня в данном вопросе.
Когда вы читаете текстовый файл в QPlainTextEdit
преобразование выполняется автоматически и за кадром. Чтение QString
из QByteArray
это также может быть сделано автоматически (при условии, что для вашей локали и настроек кодека установлены UTF-8), или они могут быть выполнены явно с помощью toUtf8() или fromUtf8(), как в моем коде выше.
Преобразование в другом направлении может быть эффективно сделано неявно (за кадром) или явно с помощью следующего кода:
ba += *si; // Depends on the UTF-8 codec
или же
ba += QString(*si).toUtf8(); // UTF-8 explicitly
где ba
это QByteArray
а также si
является QString::const_iterator
, Они делают то же самое (при условии, что кодек установлен в UTF-8). Они оба преобразуют следующий (один) символ из QChar
указал в пределах QString
в результате чего добавляется один или несколько байтов в ba
,
Все, что я пытаюсь сделать, это обратное преобразование только для одного символа за раз, эффективно. Внутренне это делается для каждого конвертируемого персонажа, и я уверен, что это делается очень эффективно.
Проблема с QString::fromUtf8(p,n)
в том, что n
количество байтов для обработки, а не количество символов для преобразования. Следовательно, вы должны учитывать наибольшее количество байтов, которое может быть 3 (или 4, если он фактически обрабатывает суррогатные пары). Поэтому, если вам нужен только следующий символ, вы должны быть готовы обработать несколько байтов, и они преобразуются, а затем отбрасываются, если результат QString
с более чем одним персонажем.
Q: есть функция преобразования, которая делает этот один символ за один раз?
1 ответ
Вы хотите использовать QTextDecoder.
Это согласно документации:
Класс QTextDecoder предоставляет основанный на состоянии декодер. Текстовый декодер преобразует текст из закодированного текстового формата в Unicode, используя определенный кодек. Декодер преобразует текст в этом формате в Unicode, помня любое состояние, которое требуется между вызовами.
Здесь важно государство. QString и QTextCodec не имеют состояния, поэтому они работают с целыми строками, от начала до конца.
QTextDecoder, с другой стороны, позволяет вам работать с байтовыми буферами по одному байту за раз, поддерживая состояние между вызовами, чтобы вызывающая сторона знала, была ли последовательность UTF-8 только частично декодирована.
Например:
QTextDecoder decoder(QTextCodec::codecForName("UTF-8"));
QString result;
for (int i = 0; i < bytearray.size(); i++) {
result = decoder.toUnicode(bytearray.constData() + i, 1);
if (!result.isEmpty()) {
break; // we got our character !
}
}
Логическое обоснование этого цикла состоит в том, что до тех пор, пока декодер не сможет декодировать полный символ UTF-8, он будет возвращать пустую строку.
Как только это будет возможно, результирующая строка будет содержать один декодированный символ Юникода.
Этот цикл максимально эффективен, и запоминая индекс цикла, можно получить следующие символы таким же образом.