Как распознать кодировку текстового файла?

  • Автор темы Автор темы Nogr1k
  • Дата начала Дата начала
Статус
Закрыто для дальнейших ответов.
N

Nogr1k

Доброго времени суток. Столкнулся с проблемой кодировки.
В приложении необходимо обеспечить поддержку кодировок UTF-8 и ANSI (win1251) при открытии текстовых файлов.
Я читаю файл (StreamReader.ReadToEnd()) и полученную строку необходимо, если она в ANSI, преобразовать в UTF-8.
Возможно ли определить кодировку файла программно?
Я пробовал читать данные в бинарном виде, затем анализировать их побайтно, но этот метод не очень эффективен :)
Возможно я просто плохо читал доки и существует метод упрощающий эту операцию.
Может кто-нибудь сталкивался с подобной проблемой? Спасибо.
 
И все же мне удалось решить проблему :)

Сначала код:

Код:
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).

Код, конечно, громоздкий, но для демонтрации самого алгоритма вполне достаточный :)
 
Статус
Закрыто для дальнейших ответов.
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!