Печать байтов строки UTF-8 в C - PullRequest
0 голосов
/ 05 ноября 2018

Я хотел напечатать отдельные байты слова «česnek», ожидая печати 7 байтов, потому что «č» закодирован в 2 байта, что он делает, но печатает символ мусора, такой как знак вопроса в терминале. Если я распечатываю целочисленное значение, я получаю эту последовательность.

-60 -115 101 115 110 101 107

Почему первые два числа отрицательны? Вот код, который я использовал, чтобы попробовать это.

 char *utfstring = "česnek";
 for(size_t i = 0; i < strlen(utfstring); i++) {
 printf("%c ", utfstring[i]);
 }
 for(size_t i = 0; i < strlen(utfstring); i++) {
 printf("%d ", utfstring[i]);
 }

Я ожидал, что первые два значения будут c4 8d, потому что č кодируется следующим образом: https://www.utf8 -chartable.de / unicode-utf8-table.pl? Start = 256 & unicodeinhtml = dec

Ответы [ 3 ]

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

Ваш for -цикл перебирает символьное значение побайтно, , когда UTF-представление является многобайтовым.

char *utfstring = "česnek"; - это длиной более шести байтов! Поскольку первый «символ» в этой строке занимает более одного байта. (Хитрость представления UTF заключается в том, что каждый из байтов самокодируется таким образом, что, изучая двоичное содержимое каждого байта в отдельности, вы можете надежно определить, какой это «тип» байта и куда он падает [если применимо] в многобайтовой последовательности.)

Ваша логика пытается использовать форматы %c и %d для этих байтов, когда, возможно, ни один из них не является наиболее подходящим. «В этом [человеческом] контексте, это не символы и не целые числа». Попробуйте %x ... шестнадцатеричный. «Покажи мне биты».

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

Используйте (unsigned char)utfstring[i] или 0xFF & utfstring[i], чтобы получить шестнадцатеричный вывод следующим образом:

char *utfstring = u8"česnek";
for(size_t i = 0; i < strlen(utfstring); i++)
    printf("%02X ", 0xFF & utfstring[i]);

выход:

"C4 8D 65 73 6E 65 6B"

Первый буквенный символ č не может быть представлен одним байтом в UTF8. Если вы печатаете utfstring по одному байту за раз, то кодировка UTF8 нарушается.

Он должен быть напечатан как u8"č" или u8"\xC4\x8D"

В общем случае вам понадобится библиотека Unicode, например, iconv, если вы хотите разбить последовательность байтов на отдельные кодовые точки Unicode. Если вы просто пытаетесь найти č, используйте стандартные строковые функции, например strstr(utfstring, u8"č").

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

Во-первых, подпись char определяется реализацией . Кроме того, вы говорите printf() напечатать номер со знаком, используя %d. Чтобы переносить их в виде чисел без знака, необходимо привести их к unsigned и распечатать, используя спецификатор формата %u :

printf("%u ", (unsigned char) utfstring[i]);

Это позаботится об отрицательных числах, но у вас есть другая проблема: стандарт C не требует, чтобы компилятор принимал символы в кодировке UTF-8 в исходном коде. Только небольшой набор основных символов гарантируется стандартом. Возможно, вам придется проверить документацию для вашего конкретного компилятора и стандартной библиотеки, чтобы увидеть, как это обрабатывается. Вы можете получить UTF-8, некоторую другую кодировку или мусор; и что бы вы ни получили, это не портативно. Если это звучит неубедительно, вы правы, это так - C / C ++ давно играет в догонялки, когда дело доходит до i18n.

Хорошая новость в том, что дела налаживаются. Если ваш компилятор поддерживает C11, вы можете и должны использовать строковые литералы UTF-8 для переносимого кодирования кодовых точек UTF-8 в строках.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...