Как обнаружить кодирование символов текстового файла?

StackOverflow https://stackoverflow.com/questions/4520184

Вопрос

Я пытаюсь обнаружить, какой кодирование символов используется в моем файле.

Я стараюсь с этим кодом, чтобы получить стандартную кодировку

public static Encoding GetFileEncoding(string srcFile)
    {
      // *** Use Default of Encoding.Default (Ansi CodePage)
      Encoding enc = Encoding.Default;

      // *** Detect byte order mark if any - otherwise assume default
      byte[] buffer = new byte[5];
      FileStream file = new FileStream(srcFile, FileMode.Open);
      file.Read(buffer, 0, 5);
      file.Close();

      if (buffer[0] == 0xef && buffer[1] == 0xbb && buffer[2] == 0xbf)
        enc = Encoding.UTF8;
      else if (buffer[0] == 0xfe && buffer[1] == 0xff)
        enc = Encoding.Unicode;
      else if (buffer[0] == 0 && buffer[1] == 0 && buffer[2] == 0xfe && buffer[3] == 0xff)
        enc = Encoding.UTF32;
      else if (buffer[0] == 0x2b && buffer[1] == 0x2f && buffer[2] == 0x76)
        enc = Encoding.UTF7;
      else if (buffer[0] == 0xFE && buffer[1] == 0xFF)      
        // 1201 unicodeFFFE Unicode (Big-Endian)
        enc = Encoding.GetEncoding(1201);      
      else if (buffer[0] == 0xFF && buffer[1] == 0xFE)      
        // 1200 utf-16 Unicode
        enc = Encoding.GetEncoding(1200);


      return enc;
    }

Мои пять первых байтов - 60, 118, 56, 46 и 49.

Есть ли диаграмма, которая показывает, какая кодировка соответствует этим пять первых байтов?

Это было полезно?

Решение

Вы не можете зависеть от файла, имеющего родитель. UTF-8 не требует этого. А кодировки, не являющиеся юникодом, даже не имеют отношения. Однако есть другие способы обнаружения кодирования.

UTF-32

Bom - 00 00 fe ff (для be) или ff fe 00 00 (для LE).

Но UTF-32 легко обнаружить даже без рода. Это связано с тем, что диапазон точек кода Unicode ограничен U+10FFFF, и, таким образом, единицы UTF-32 всегда имеют шаблон 00 {00-10} xx xx (для be) или xx xx {00-10} 00 (для le) Анкет Если данные имеют длину, которая кратно 4, и следует за одним из этих шаблонов, вы можете безопасно предположить, что это UTF-32. Ложные позитивы практически невозможно из-за редкости 00 байтов в байто-ориентированных кодировках.

US-ASCII

Нет, но вам не нужно. ASCII может быть легко идентифицирован из-за отсутствия байтов в диапазоне 80-FF.

UTF-8

Bom - это ef bb bf. Но вы не можете полагаться на это. Многие файлы UTF-8 не имеют отношения, особенно если они возникают в системах, не являющихся Windows.

Но вы можете с уверенностью предположить, что если файл проверяет как UTF-8, он является UTF-8. Ложные позитивы редки.

В частности, учитывая, что данные не являются ASCII, ложная положительная скорость для 2-байтовой последовательности составляет всего 3,9% (1920/49152). Для 7-байтовой последовательности это менее 1%. Для 12-байтовой последовательности это менее 0,1%. Для 24-байтовой последовательности это менее 1 на миллион.

UTF-16

Bom - это fe ff (for be) или ff fe (для Le). Обратите внимание, что BOM UTF-16LE находится в начале UTF-32LE BOM, поэтому сначала проверьте UTF-32.

Если у вас есть файл, который состоит в основном из символов ISO-8859-1, наличие половины байтов файла 00 также будет сильным показателем UTF-16.

В противном случае, единственный надежный способ распознавания UTF-16 без рода-найти суррогатные пары (D [8-B] XX D [CF] XX), но не BMP символы слишком редко используются, чтобы сделать этот подход практичным Анкет

XML

Если ваш файл начинается с байтов 3C 3F 78 6D 6C (т.е. символы ASCII " encoding= декларация. Если присутствовать, то используйте это кодирование. Если отсутствовать, предположим, что UTF-8, который является кодированием XML по умолчанию.

Если вам нужно поддерживать EBCDIC, также ищите эквивалентную последовательность 4C 6F A7 94 93.

В общем, если у вас есть формат файла, который содержит объявление кодирования, то ищите это объявление, а не пытаться угадать кодирование.

Ни один из вышеперечисленных

Существуют сотни других средств, которые требуют больше усилий для обнаружения. Я рекомендую попробовать Детектор Charset Mozilla или же это порт .NET.

Разумный дефолт

Если вы исключили кодировки UTF и не имеете кодирующего объявления или статистического обнаружения, которое указывает на другое кодирование, предположим ISO-8859-1 или тесно связанный Windows-1252. Анкет (Обратите внимание, что последний стандарт HTML требует объявление «ISO-8859-1», которое будет интерпретировано как Windows-1252.) Кодовая страница Windows по умолчанию для английского языка (и других популярных языков, таких как испанский, португальский, немецкий и французский), это наиболее часто встречающиеся кодиры, кроме как кроме, кроме как UTF-8.

Другие советы

Если вы хотите получить «простое» решение, вы можете найти этот класс, я собрал полезным:

http://www.architectshack.com/textfileencodingdetector.ashx

Сначала он выполняет автоматическое обнаружение BOM, а затем пытается дифференцировать кодирования Unicode без BOM, по сравнению с некоторым другим кодированием по умолчанию (обычно Windows-1252, неправильно помеченный как кодирование. ASCII в .NET).

Как отмечалось выше, более сложное решение с участием Nchardet или Mlang может быть более уместным, и, как я отмечаю на странице обзора этого класса, лучше всего обеспечить некоторую форму интерактивности с пользователем, если это вообще, потому что просто есть просто невозможен на 100% обнаружение!

Использовать StreamReader и направить его, чтобы обнаружить кодирование для вас:

using (var reader = new System.IO.StreamReader(path, true))
{
    var currentEncoding = reader.CurrentEncoding;
}

И использовать Идентификаторы кодовой страницы https://msdn.microsoft.com/en-us/library/windows/desktop/dd317756(v=vs.85).aspxЧтобы переключить логику в зависимости от этого.

Несколько ответов здесь, но никто не опубликовал полезный код.

Вот мой код, который обнаруживает все кодирования, которые Microsoft обнаруживает в Framework 4 в классе StreamReader.

Очевидно, что вы должны назвать эту функцию сразу после открытия потока, прежде чем читать что -либо еще из потока, потому что BOM являются первыми байтами в потоке.

Эта функция требует потока, который может искать (например, FileStream). Если у вас есть поток, который не может искать, вы должны написать более сложный код, который возвращает байтовый буфер с байтами, которые уже были прочитаны, но это не родилось.

/// <summary>
/// UTF8    : EF BB BF
/// UTF16 BE: FE FF
/// UTF16 LE: FF FE
/// UTF32 BE: 00 00 FE FF
/// UTF32 LE: FF FE 00 00
/// </summary>
public static Encoding DetectEncoding(Stream i_Stream)
{
    if (!i_Stream.CanSeek || !i_Stream.CanRead)
        throw new Exception("DetectEncoding() requires a seekable and readable Stream");

    // Try to read 4 bytes. If the stream is shorter, less bytes will be read.
    Byte[] u8_Buf = new Byte[4];
    int s32_Count = i_Stream.Read(u8_Buf, 0, 4);
    if (s32_Count >= 2)
    {
        if (u8_Buf[0] == 0xFE && u8_Buf[1] == 0xFF)
        {
            i_Stream.Position = 2;
            return new UnicodeEncoding(true, true);
        }

        if (u8_Buf[0] == 0xFF && u8_Buf[1] == 0xFE)
        {
            if (s32_Count >= 4 && u8_Buf[2] == 0 && u8_Buf[3] == 0)
            {
                i_Stream.Position = 4;
                return new UTF32Encoding(false, true);
            }
            else
            {
                i_Stream.Position = 2;
                return new UnicodeEncoding(false, true);
            }
        }

        if (s32_Count >= 3 && u8_Buf[0] == 0xEF && u8_Buf[1] == 0xBB && u8_Buf[2] == 0xBF)
        {
            i_Stream.Position = 3;
            return Encoding.UTF8;
        }

        if (s32_Count >= 4 && u8_Buf[0] == 0 && u8_Buf[1] == 0 && u8_Buf[2] == 0xFE && u8_Buf[3] == 0xFF)
        {
            i_Stream.Position = 4;
            return new UTF32Encoding(true, true);
        }
    }

    i_Stream.Position = 0;
    return Encoding.Default;
}

Если ваш файл начинается с байтов 60, 118, 56, 46 и 49, у вас есть неоднозначный случай. Это может быть UTF-8 (без BOM) или любые из одиночных байтовых кодировков, таких как ASCII, ANSI, ISO-8859-1 и т. Д.

я использую Ude Это порт C# Mozilla Universal Detector. Это прост в использовании и дает действительно хорошие результаты.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top