Страницы

Поиск по вопросам

пятница, 9 ноября 2018 г.

Как считать символ с мультибайтовой строки?

Есть мультибайтовая строка, длина её меряется в мегабайтах, нужно считывать в цикле посимвольно, как считать один символ с мультибайтовой строки?(не используя uchar.h)


Ответ

Берем очередной байт из строки. Предполагая, что это первый байт utf-8 символа
unsigned char b=...; // тут проверяемый байт (обязательно unsigned !!!) if(b<=0x7F) это однобайтовый символ, можем выдавать его и проверять следующий else if(b>=0xF8) ... это не unicode символ, или более новый стандарт с более чем 4х байтовыми символами else if(b>=0xF0) ... это 4х байтовый символ. т.е. берем еще следующие 3 байта else if(b>=0xE0) ... это 3х байтовый символ. т.е. берем еще следующие 2 байта else if(b>=0xC0) ... это 2х байтовый символ. т.е. берем еще следующий байт else ... b - совершенно точно один из серединных байт символа, мы потеряли первый байт
Если символ длиной более 1 байта, то все последующие байты символа должны быть в диапазоне b>=0x80 && b<0xC0
Написал по стандарту RFC3629, надеюсь нигде не ошибся. Можно еще посмотреть код готовых библиотек.
Эх. Обожаю делать велосипеды, вот накидал пример, с разбором кодов символов. Получаемые коды для русских букв сверил с выдаваемых функцией Javascript charCodeAt - совпали. Внимание: собрано на коленке. нет проверок, что строка закончилась в середине символа, при неправильной unicode строке возможен выход за пределы массива ! Трехбайтные и четырехбайтные символы так же не проверены, т.к. не знаю китайского. Так же нет проверки 2го и последующего байта unicode на корректность, тупо сбрасываем старшие 2 бита и используем.
#include #include
unsigned char *s="Test string. Тестовая строка"; int main() { int len=strlen(s); int i; int sim_code; // Сюда собираем код очередного символа for(i=0;i=0xF8) { printf("Не unicode 6.0 (RFC3629) символ %X",s[i]); continue; } else if(s[i]>=0xF0) { sim_code=( ((s[i]&0x07)<<18) | ((s[i+1]&0x3F)<<12) | ((s[i+2]&0x3F)<<6) | (s[i+3]&0x3F) ); i+=3; } else if(s[i]>=0xE0) { sim_code=( ((s[i]&0x0F)<<12) | ((s[i+1]&0x3F)<<6) | (s[i+2]&0x3F) ); i+=2; } else if(s[i]>=0xC0) { sim_code=( ((s[i]&0x1F)<<6) | (s[i+1] & 0x3F) ); i++; } else { printf("Пропущен первый байт unicode символа !!! (%X)",s[i]); continue; } printf("%d ",sim_code); } }
Универсальный способ получения длины текущего символа:
unsigned char b=s[i]; // Берем первый байт символа int n; // длина символа if(b<=0x7F) n=1; ... это однобайтовый символ, работаем с ним как есть else for(n=0; b & 0x80; n++) b<<=1; // после цикла n=полной длине в байтах, включая текущий байт

Комментариев нет:

Отправить комментарий