Запись от AZM на субдомене electronics-and-mechanics |
Все записи на субдомене: Электроника и механика (записки от AZM) |
Функция определения UTF-8 кодировки (определить что текст в UTF-8) |
Прежде всего определимся, что это будет современный текст на современном языке, а не на языке вымерших народов или состоящий по большей части из редких китайских иероглифов. Соответственно, UTF-8 на современных языках не будет содержать символов состоящих из более чем 3 байта, символы из 4 байт это музыкальные символы, редкие китайские иероглифы и вымершие формы письменности, а символы с 5 и 6 байт не используются в Unicode. Собственно код на языке C (си): // Определяет длину в байтах считая первый байт последовательности кодирующей UTF-8 символ // Зная, что длина кодируется в первом байте так: 0b110xxxxx для 2 байт, 0b1110xxxx для трёх и так далее, в общем число бит равных 1 слева = число байт кодирующих символ, потом бит 0 что бы показать конец этого безобразия unsigned int get_lenCharInUTF8(unsigned char inputchar){ if ((inputchar & 0b11000000) == 0b10000000){return 1;} if ((inputchar & 0b11100000) == 0b11000000){return 2;} if ((inputchar & 0b11110000) == 0b11100000){return 3;} if ((inputchar & 0b11111000) == 0b11110000){return 4;} if ((inputchar & 0b11111100) == 0b11111000){return 5;} return 0; } // Возвращает TRUE если текст в UTF-8 иначе FALSE bool is_TextUTF8(unsigned char *inputtxt, unsigned int inputtxtlen){ unsigned int tmpsymleninfileutf; unsigned int loadNoUTFsymbol=0; unsigned int loadUTFsymbol=0; unsigned char tempsyminfile; // if (inputtxt[0]==0xef && inputtxt[1]==0xbb && inputtxt[2]==0xbf){return TRUE;} // это если верите в BOM, то раскомментируйте эту строку, иначе будем всё же анализировать текст for (unsigned int ix=0; ix < inputtxtlen; ix++){ tempsyminfile=inputtxt[ix]; if (tempsyminfile >127 && tempsyminfile != 0xfe && tempsyminfile != 0xff){ tmpsymleninfileutf=get_lenCharInUTF8(tempsyminfile); if (tmpsymleninfileutf ==0){ loadNoUTFsymbol++; }else{ if (tmpsymleninfileutf >3){loadNoUTFsymbol++;} tempsyminfile=Temp_text_buffer[ix+1]; if (tempsyminfile < 0x80 || tempsyminfile > 0xBF){ loadNoUTFsymbol++; }else{ tempsyminfile=Temp_text_buffer[ix+tmpsymleninfileutf]; if (tempsyminfile >127 && tempsyminfile != 0xfe && tempsyminfile != 0xff){ if (get_lenCharInUTF8(tempsyminfile) !=0){ix=ix+tmpsymleninfileutf-1; loadUTFsymbol++;}else{loadNoUTFsymbol++;} }else{loadNoUTFsymbol++;} }} }} if (loadUTFsymbol > loadNoUTFsymbol){return TRUE;} return FALSE; }Для желающих портитовать на другие языки или просто разобраться с процессом, поясню как же это работает. UTF-8 последовательности имеют следующий вид: символ 1 [первый байт если более 127 то должен содержать длину последовательности] [второй байт может содержать значения от 80 до BF включительно] [третий байт попадающий под правила второго] [четвёртый байт попадающий под правила второго] ... ... символ 2 [первый байт если более 127 то должен содержать длину последовательности] [второй байт может содержать значения от 80 до BF включительно] [третий байт попадающий под правила второго] [четвёртый байт попадающий под правила второго] ... ... Если первый байт менее 127 то в нём код символа аналогичный коду ASCII (латинские буквы, знаки препинания, цифры, ...). То есть если весь текст состоит лишь из латинницы и не имеет символов русского или другого наказанного UTF-8 языка, то нет никакой разницы UTF-8 это или старое доброе ASCII. Байты кодировки UTF-8 не могут содержать значений FE и FF (ни первый байт ни байты данных), следовательно если мы встречаем хоть один байт с значением FE ("ю" в win-1251) и FF ("я" в win-1251) теоретически можно быть увереным что данные не в кодировке UTF-8. На практике данные могут быть просто повреждены, по этому функция всё же анализирует весь объём данных. Зная это, рассмотрим, алгоритм функции is_TextUTF8: 1. Берём байт текста. 2. Если байт имеет значение менее 128 то ++ индекса откуда брать байты и к пункту 1. 2. Передаём функции определяющей длину последовательности UTF-8 3. Если длина определилась не корректно, то ++ счётчику неUTFбукв и ++ индекса откуда брать байты и к пункту 1. 4. Берём следующий байт и смотрим, если он в рамках диапазона данных UTF-8 то ++ счётчику UTFбукв, к индексу откуда брать байты прибавляем определившуюся ранее длину и к пункту 1. Далее, после того как проехались по всем данным просто сравниваем, чего больше - "неUTFбукв" или "UTFбукв". |
Добавлено: 3572 дн 11 час 41 мин 35 сек назад | Внесений правок: 0 | Последняя правка: нет данных |