18+ Некоторые материалы сайта могут содержать информацию, запрещенную для детей.

Запись от 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букв".

Добавлено: 3356 дн 18 час 23 мин 41 сек назад | Внесений правок: 0 | Последняя правка: нет данных



Электроника и механика (записки от AZM)