UTF-8 и Unicode, что с 0xC0 и 0x80? - PullRequest
       9

UTF-8 и Unicode, что с 0xC0 и 0x80?

46 голосов
/ 12 октября 2010

Я читал о Unicode и UTF-8 в последние пару дней, и я часто сталкиваюсь с побитовым сравнением, подобным этому:

int strlen_utf8(char *s) 
{
  int i = 0, j = 0;
  while (s[i]) 
  {
    if ((s[i] & 0xc0) != 0x80) j++;
    i++;
  }
  return j;
}

Может кто-нибудь уточнить сравнение с 0xc0 и проверкойесли это самый значимый бит?

Спасибо!

РЕДАКТИРОВАТЬ: ANDed, а не сравнение, использовал неправильное слово;)

1 Ответ

82 голосов
/ 12 октября 2010

Это не сравнение с 0xc0, это логическая операция И с 0xc0.

Битовая маска 0xc0 равна 11 00 00 00, поэтому оператор AND извлекает только два верхних бита:

    ab cd ef gh
AND 11 00 00 00
    -- -- -- --
  = ab 00 00 00

Это тогда сравнивается с 0x80 (двоичный 10 00 00 00). Другими словами, оператор if проверяет, не равны ли верхние два бита значения 10.

«Почему?», Я слышу, вы спрашиваете. Ну, это хороший вопрос. Ответ заключается в том, что в UTF-8 все байты, которые начинаются с битовой комбинации 10, являются последующими байтами многобайтовой последовательности:

                    UTF-8
Range              Encoding  Binary value
-----------------  --------  --------------------------
U+000000-U+00007f  0xxxxxxx  0xxxxxxx

U+000080-U+0007ff  110yyyxx  00000yyy xxxxxxxx
                   10xxxxxx

U+000800-U+00ffff  1110yyyy  yyyyyyyy xxxxxxxx
                   10yyyyxx
                   10xxxxxx

U+010000-U+10ffff  11110zzz  000zzzzz yyyyyyyy xxxxxxxx
                   10zzyyyy
                   10yyyyxx
                   10xxxxxx

Итак, этот маленький фрагмент выполняет прохождение каждого байта вашей строки UTF-8 и подсчет всех байтов, которые не являются байтами продолжения (т. Е. Он получает длину строки, как объявлено). См. эту ссылку на википедию для более подробной информации и превосходную статью Джоэла Спольски для начинающих.


Кстати, интересно. Вы можете классифицировать байты в потоке UTF-8 следующим образом:

  • Если для старшего бита установлено значение 0, это значение будет одним байтом.
  • С двумя старшими битами, установленными на 10, это байт продолжения.
  • В противном случае это первый байт многобайтовой последовательности, а число начальных 1 битов указывает, сколько всего байтов для этой последовательности (110... означает два байта, 1110... означает три байта, и т.д.).
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...