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

Тема в разделе ".NET", создана пользователем Nogr1k, 26 фев 2009.

Статус темы:
Закрыта.
  1. Nogr1k

    Nogr1k Гость

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

    etc Гость

    Считайте что нет.
     
  3. Nogr1k

    Nogr1k Гость

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

    Сначала код:

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

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

Поделиться этой страницей