C как узнать кодировку файла
Перейти к содержимому

C как узнать кодировку файла

  • автор:

C как узнать кодировку файла

Вопрос в названии, нужно как то определять кодировку текстового файла и уже считывать данные на её основании.

Спросил Sergey
655 дн., 17 час., 31 мин. назад

Новые ответы

Если речь идёт о кодировке UTF-8, то можно использовать проект Utf8Checker. Проект состоит из одного класса (и интерфейса к нему), который и делает всю работу.

Ответил admax
618 дн., 1 час., 9 мин. назад

И все же мне удалось решить проблему

BinaryReader instr = new BinaryReader(File.OpenRead(path)); byte[] data = instr.ReadBytes((int)instr.BaseStream.Length); instr.Close(); // определяем BOM (EF BB BF) if (data.Length > 2 && data[0] == 0xef && data[1] == 0xbb && data[2] == 0xbf) < if (data.Length != 3) return Encoding.UTF8.GetString(data, 3, data.Length - 3); else return ""; >int i = 0; while (i < data.Length - 1) < if (data[i] >0x7f) < // не ANSI-символ if ((data[i] >> 5) == 6) < if ((i >data.Length - 2) || ((data[i + 1] >> 6) != 2)) return Encoding.GetEncoding(1251).GetString(data); i++; > else if ((data[i] >> 4) == 14) < if ((i >data.Length - 3) || ((data[i + 1] >> 6) != 2) || ((data[i + 2] >> 6) != 2)) return Encoding.GetEncoding(1251).GetString(data); i += 2; > else if ((data[i] >> 3) == 30) < if ((i >data.Length - 4) || ((data[i + 1] >> 6) != 2) || ((data[i + 2] >> 6) != 2) || ((data[i + 3] >> 6) != 2)) return Encoding.GetEncoding(1251).GetString(data); i += 3; > else < return Encoding.GetEncoding(1251).GetString(data); >> i++; > return Encoding.UTF8.GetString(data); 

Теперь немного поясню: Сиволы в UTF-8 кодируются последовательностями длиной от 1 до 4 байт (октетов).

Вот в таком формате:

U+000000-U+00007F: 0xxxxxxx (ANSI) U+000080-U+0007FF: 110xxxxx 10xxxxxx (сюда входит кириллица) U+000800-U+00FFFF: 1110xxxx 10xxxxxx 10xxxxxx U+010000-U+10FFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 

По маске первого октета определяется общее число октет в последовательности, а затем они проверяются на соответствие маске 10xxxxxx. Если какой-то байт не соответсвует маске, значит кодировка отличная от UTF-8 (в моем случае win1251).

Код, конечно, громоздкий, но для демонтрации самого алгоритма вполне достаточный

C как узнать кодировку файла

Сообщения: 133
Благодарности: 21

Имеется массив символов типа char (язык С++). Необходимо определить кодировку этих символов (UTF8 или ANSI). Возможно ли это?

——-
«Не соглашайся ни на что, кроме совершенства!» — Анонимный автор.
«Совершенство достигается только к моменту полного краха.» — К.Н.Паркинсон.

Сообщения: 1180
Благодарности: 279

если имеется какой-нить словарик с типичными фразами, то наверное можно. Если на ascii может быть написана какая-то любая фигня, то однозначно нельзя

Для отключения данного рекламного блока вам необходимо зарегистрироваться или войти с учетной записью социальной сети.

Сообщения: 1696
Благодарности: 44

EvgeniyQQQ, Не знаю, что есть ANSI. Но в ASCII не может быть символов с кодом > 127 (это 7-итная кодировка). Если же используется «расширенный» ASCII (Latin-1 или любая другая национальная кодировка), то можно просто проверить, что исходная строка содержит символы с кодом > 127 и является корректной utf-8 строкой (т.е. удовлетворяет этим требованиям: http://tools.ietf.org/html/rfc3629#section-3). Если строка достаточно большая и не в utf-8, то где-нибудь обязательно будет неправильна закодирована, и следовательно не utf-8, иначе «произвольная однобайтовая кодировка».

Сообщения: 14
Благодарности: 4

Текст, состоящий только из символов с номером меньше 128, при записи в UTF-8 превращается в обычный текст ASCII. И наоборот, в тексте UTF-8 любой байт со значением меньше 128 изображает символ ASCII с тем же кодом. Остальные символы Юникода изображаются последовательностями длиной от 2 до 6 байтов, в которых первый байт всегда имеет вид 11xxxxxx, а остальные — 10xxxxxx. Более подробно о UTF-8 посмотрите http://ru.wikipedia.org/wiki/UTF-8. Что же касается ANSI — то насколько я понимаю, это то же, что и кодировка Windows-1251, т.е. 8-битная и содержит русские символы.

Сообщения: 4
Благодарности: 1

Конфигурация компьютера
Процессор: c2d E8200
Материнская плата: p5e
Память: 2gb
Видеокарта: gf 8800gt
ОС: 2008r2

Потребовалось мне автоопределение кодировки в текстовом файле; нашёл (не претендуя на универсальность) такой выход (builder xe3):

String tst= al+af+am+bt+sn; // несколько тэгов, выделенных из fb2 файла
if( tst[1]>0x007F && UTF8Decode(tst)[1]!=0xfffd ) al=UTF8Decode(al);// нет, это не ansi!

суть в том, что UTF8Decode от русского ansi-текста возвращает строку, забитую 0xFFFD
а от английского ansi-текста или любого utf8-текста возвращает читабельный ansi-текст.

ps для fb2, понятно, надо каждый тег проверять (т.к. в utf файле могут быть смешаны и русские и английские тэги), но принцип проверки понятен.

Программное определение кодировки текстового файла из заданного списка

Задача нетривиальная: написать программу на C/C++ («чистом»), на вход которой подается путь к файлу, на выходе — кодировка этого файла с указанием точности: точно или наиболее вероятно. (содержит буквы английского и/или русского языков, и пр. символы; в файле может быть исходник программы на одном из языков программирования). Список требуемых к распознаванию кодировок: simple ASCII, CP1251 (windows 1251), ISO8859-5, CP866, KOI8-R, UTF8, UTF16-LE, UTF16-BE, UTF32-LE, UTF32-BE, UCS-2 . Ошибки: кодировка undefined или файл бинарный ( unreadable ). Задача на эвристический анализ, понятно, что однозначного решения нет. Здесь хотелось бы собрать воедино все признаки отличия этих кодировок друг от друга, а также конфликтование этих признаков между собой, чтобы составить алгоритм. Существуют BOM ( Byte Order Mark ) для UTF8 (может не быть), для UTF16LE(BE) , UTF32LE(BE) , по которым их легко можно определить, но в таком случае возникает тонкая грань между UCS-2 и UTF-16 — возникает проблема в их различении. Имеются неполные решения задачи: команда file -i [path] для UNIX (есть порт для WIN ), которая по специальной таблице встречаемости кодов символов в разных кодировках умеет определять ASCII , ISO8859-5 (которую путает с Win-1251 ), UTF8, UTF16, EBCDIC , но 8-битные non-ISO кодировки именует 8-bit unknown . По каким признакам можно отличить KOI8-R, WIN-1251, ISO8859-5, CP866, ASCII (т.е. все однобайтовые в данном случае)? UCS-2 = UTF16 без «суррогатных пар». Существует также утилита ENCA для UNIX , которая умеет определять кодировки в более широком диапазоне, но принцип работы ее непонятен. Заранее благодарю за любую помощь.

Отслеживать
30.9k 13 13 золотых знаков 96 96 серебряных знаков 157 157 бронзовых знаков
задан 10 июл 2012 в 23:24
201 2 2 золотых знака 3 3 серебряных знака 5 5 бронзовых знаков

Существуют вроде еще методы определения кодировки по разделителям строк, абзацев и пр. CR, LF, CR+LF — только должного описания, какой разделитель присущ какой кодировке найти не удалось.

11 июл 2012 в 1:50
11 июл 2012 в 8:50

@Kalash По разделителям строк кодировку не определить, разве что только вероятную платформу (win / unix / mac) , на которой создан данный файл.

11 июл 2012 в 9:18

Я делал такую программу (just for fun), но 1) для русского языка 2) только для однобайтных кодировок (включая UTF-8) — «Угадывание» проводится на основе статистики частоты символов в русском тексте. Просто взял несколько книжек и набрал статистику русских букв. Т.е. предполагая, что файл в данной кодировке, считаем частоты букв и сравниваем с «эталоном». Для какой кодировки отклонение меньше, ту и считаем правильной. Понятно, что если файл не в UTF-8, то это быстро отлавливается. Ясно, что такой подход работает в основном для «осмысленных» текстов.

C как узнать кодировку файла

Ну, почему-же. Можно. Набрать статистику распределения символов.
Для русского языка часто встречающиеся символы ОТЕНАР.

Участник клуба
Регистрация: 12.10.2007
Сообщений: 1,204

Вот схема:
объявляем два массива
WinCounts : array [char] of integer; // Количество символов в кодировке Win
DosCounts : array [char] of integer; // Количество сисволов в кодировке DOS

Очередную строку файла обработываем:

if length(S) = 0 then exit;

SetLength(S2, length(S));
OEMToChar(PChar(S), PChar(S2)); /// DOWtoWIN
S1 := Upper(S);
S2 := Upper(S2);
for i:=1 to length(S1) do begin
Inc(WinCounts[S1[i]]);
Inc(DosCounts[S2[i]]);
end;

т.е. увеличиваем количество символов в обеих кодировках.
Чем больше строк обработано, тем лучше, но достаточно даже одной строки.

После обработки части файла:

M := (WinCounts[‘О’] + WinCounts[‘Т’] + WinCounts[‘Е’] + WinCounts[‘H’] + WinCounts[‘А’]);
if (DosCounts[‘О’] + DosCounts[‘Т’] + DosCounts[‘Е’] + DosCounts[‘H’] + DosCounts[‘А’]) > M
then CodePage := cpDOS;

Форумчанин
Регистрация: 25.09.2007
Сообщений: 189
это не 100% вариант, думаю (хотя спорить не хочется)
Пользователь
Регистрация: 01.11.2007
Сообщений: 33

[b]alexBlack[b] видите ли в чем дело, мне нужно переводить из DOS кодировки в Win но я не знаю в какой кодировке пребывает файл в данный момент. Функция OEMToChar переводит (и непереводит если это не надо, хотя не уверен не тестировал ) например считав строку из файла прогоняю ее через OEMToChar и она меняется если эта строка в DOS кодировке и не меняется если в WIN кодировке! Я хочу добиться именно такого эффекта, я написал свою функцию OEMToChar, но если строка уже в Win код-ке она искажает символы входящие в диапазон от ‘р’до ‘я’

Участник клуба
Регистрация: 12.10.2007
Сообщений: 1,204
Сообщение от PuzzleC

[b]alexBlack[b] видите ли в чем дело, мне нужно переводить из DOS кодировки в Win но я не знаю в какой кодировке пребывает файл в данный момент. Функция OEMToChar переводит (и непереводит если это не надо, хотя не уверен не тестировал ) например считав строку из файла прогоняю ее через OEMToChar и она меняется если эта строка в DOS кодировке и не меняется если в WIN кодировке! Я хочу добиться именно такого эффекта, я написал свою функцию OEMToChar, но если строка уже в Win код-ке она искажает символы входящие в диапазон от ‘р’до ‘я’

То есть я не достаточно подорбно объяснил. Итак. Сначала нужно узнать в какой кодировке файл. Для этого его нужно просканировать (или хотя-бы несколько строк). Для каждой строки файла S

S1 = upper(S) — исходная строка
S2 = upper(OEMtoChar(S)) — та же строка в другой кодировке

Мы используем только верхний регистр символов, т.к. нас интересует частота встречаемости.

Увеличиваем количество символов
for i:=1 to length(S1) do begin
Inc(WinCounts[S1[i]]);
Inc(DosCounts[S2[i]]);
end;

Когда все строки проанализированы, проверяем частоты встречаемости символов ОТЕНАР в обеих кодировках

M := (WinCounts[‘О’] + WinCounts[‘Т’] + WinCounts[‘Е’] + WinCounts[‘H’] + WinCounts[‘А’]);

if (DosCounts[‘О’] + DosCounts[‘Т’] + DosCounts[‘Е’] + DosCounts[‘H’] + DosCounts[‘А’]) > M
then CodePage := cpDOS;
else CodePage := cpWIN;

И уже теперь, если cpDOS, то переводим строку в кодировку WIN.

Как уже было замечено, 100% определения не достигнуть. Но, по моим наблюдениям такой алгоритм правильно срабатывал по одной строке.

Надеюсь, я достаточно понятно объяснил.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *