C: Самый эффективный способ определить, сколько байтов потребуется для строки UTF-16 из строки UTF-8. - PullRequest
6 голосов
/ 20 апреля 2011

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

  • Учитывая строку UTF-8, сколько байтов необходимо для кодирования UTF-16 той же строки.
  • Предположим, что строка UTF-8 уже была проверена. У него нет спецификации, нет слишком длинных последовательностей, нет недопустимых последовательностей, он заканчивается нулем. Это не CESU-8 .
  • Полная поддержка UTF-16 с суррогатами должна поддерживаться.

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

Лучший UTF-8 для кода кода, который я когда-либо видел, использует методы векторизации, так что мне интересно, возможно ли это и здесь?

Ответы [ 3 ]

5 голосов
/ 20 апреля 2011

Эффективность - это всегда соотношение скорости и размера. Если скорость предпочтительнее размера, то самый эффективный способ - просто угадать, исходя из длины строки источника.

Есть 4 случая, которые необходимо рассмотреть, просто выберите худший случай в качестве конечного размера буфера:

  • U + 0000-U + 007F - будет кодировать до 1 байта в utf8 и 2 байта на символ в utf16. (1: 2 = x2)
  • U + 0080-U + 07FF - кодируется в 2-байтовые последовательности utf8 или 2 байта на символ utf16 символов. (2: 2 = x1)
  • U + 0800-U + FFFF - сохраняются в виде 3-байтовых последовательностей utf8, но по-прежнему умещаются в один символ utf16. (3: 2 = х.67)
  • U + 10000-U + 10FFFF - сохраняются как 4-байтовые последовательности utf8 или суррогатные пары в utf16. (4: 4 = x1)

Коэффициент расширения в худшем случае - при переводе U + 0000-U + 007f из utf8 в utf16: буфер, в свою очередь, просто должен быть в два раза больше исходной строки. Любая другая кодовая точка Unicode приводит к одинаковому размеру или меньшему байтовому распределению, когда кодируется как utf16 как utf8.

3 голосов
/ 20 апреля 2011

Очень просто: подсчитать количество байтов заголовка, дважды считать байты F0 и выше.

В коде:

size_t count(unsigned char *s)
{
    size_t l;
    for (l=0; *s; s++) l+=(*s-0x80U>=0x40)+(*s>=0xf0);
    return l;
}

Примечание. Эта функция возвращает длину в кодовых единицах UTF-16. Если вам нужно необходимое количество байтов, умножьте на 2. Если вы собираетесь хранить нулевой терминатор, вам также необходимо учитывать место для этого (одна дополнительная единица кода / два дополнительных байта).

2 голосов
/ 20 апреля 2011

Это не алгоритм, но если я правильно понимаю, правила таковы:

  • каждый байт с MSB 0 добавляет 2 байта (1 единица кода UTF-16)
    • этот байт представляет одну кодовую точку Unicode в диапазоне U + 0000 - U + 007F
  • каждый байт, имеющий MSB 110 или 1110, добавляет 2 байта (1Кодовая единица UTF-16)
    • эти байты начинают 2- и 3-байтовые последовательности соответственно, которые представляют кодовые точки Unicode в диапазоне U + 0080 - U + FFFF
  • каждыйБайт с установленным 4-мя старшими битами (то есть начиная с 1111) добавляет 4 байта (2 единицы кода UTF-16)
    • , эти байты запускают 4-байтовые последовательности, которые охватывают «остальную часть» диапазона Unicode, чтоможет быть представлен с низким и высоким суррогатом в UTF-16
  • каждый второй байт (т. е. те, которые начинаются с 10) может быть пропущен
    • эти байты ужеподсчитано с остальными.

Я не эксперт C, но это выглядит легко вектоrizable.

...