Как я могу определить кодировку/кодовую страницу текстового файла

В нашем приложении мы получаем текстовые файлы (.txt, .csv и т.д.) из разных источников. При чтении эти файлы иногда содержат мусор, потому что файлы, созданные в другой/неизвестной кодовой странице.

Есть ли способ (автоматически) определить кодовую страницу текстового файла?

detectEncodingFromByteOrderMarks, в конструкторе StreamReader работает для UTF8 и других отмеченных в Unicode файлов, но я ищу способ обнаружения кодовых страниц, например ibm850, windows1252.


Спасибо за ваши ответы, вот что я сделал.

Файлы, которые мы получаем, принадлежат конечным пользователям, они не имеют понятия о кодовых страницах. Приемники также являются конечными пользователями, и теперь это то, что они знают о кодовых страницах: Codepages существуют и раздражают.

Решение:

  • Откройте полученный файл в "Блокноте", посмотрите на искаженный фрагмент текста. Если кого-то зовут Франсуа или что-то, с вашим человеческим интеллектом, вы можете догадаться об этом.
  • Я создал небольшое приложение, которое пользователь может использовать для открытия файла, и введите текст, который пользователь знает, что он появится в файле, когда будет использована правильная кодовая страница.
  • Прокрутите все кодовые страницы и отобразите те, которые дают решение с предоставленным пользователем текстом.
  • Если по мере появления одной кодовой страницы попросите пользователя указать больше текста.

Ответы

Ответ 1

Вы не можете обнаружить кодовую страницу, вам нужно сказать об этом. Вы можете анализировать байты и угадывать их, но это может дать некоторые странные (иногда забавные) результаты. Я не могу найти его сейчас, но я уверен, что Блокнот можно обмануть, показывая английский текст на китайском языке.

В любом случае, это то, что вам нужно прочитать: Абсолютный минимум Каждый разработчик программного обеспечения Абсолютно, положительно должен знать о Unicode и наборах символов (нет оправданий!).

В частности, Джоэл говорит:

Самый важный факт о кодировании

Если вы полностью забудете все, что я только что объяснил, помните один чрезвычайно важный факт. Не имеет смысла иметь строку, не зная, какую кодировку она использует. Вы больше не можете засунуть голову в песок и притвориться, что "простой" текст - ASCII. Нет такой вещи, как обычный текст.

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

Ответ 2

Если вы хотите обнаружить кодировки, отличные от UTF (т.е. нет спецификации), вы, в основном, используете эвристику и статистический анализ текста. Возможно, вы захотите взглянуть на документ Mozilla для обнаружения универсальной кодировки (те же ссылки, с лучшим форматированием через Wayback Machine).

Ответ 3

Вы пробовали порт С# для универсального детектора Charset Mozilla

Пример из http://code.google.com/p/ude/

public static void Main(String[] args)
{
    string filename = args[0];
    using (FileStream fs = File.OpenRead(filename)) {
        Ude.CharsetDetector cdet = new Ude.CharsetDetector();
        cdet.Feed(fs);
        cdet.DataEnd();
        if (cdet.Charset != null) {
            Console.WriteLine("Charset: {0}, confidence: {1}", 
                 cdet.Charset, cdet.Confidence);
        } else {
            Console.WriteLine("Detection failed.");
        }
    }
}    

Ответ 4

Вы не можете обнаружить кодовую страницу

Это явно неверно. Каждый веб-браузер имеет какой-то универсальный детектор штриховок для обработки страниц, которые не имеют никаких указаний на кодировку. У Firefox есть одно. Вы можете загрузить код и посмотреть, как он это делает. См. Документацию здесь. В принципе, это эвристика, но она работает очень хорошо.

Учитывая разумный объем текста, можно даже обнаружить язык.

Вот еще один, который я только что нашел с помощью Google:

Ответ 5

Я знаю это очень поздно для этого вопроса, и это решение не понравится некоторым (из-за его предвзятости, ориентированной на английский язык, и его отсутствия статистического/эмпирического тестирования), но для меня это очень хорошо работало, особенно для обработки загруженных Данные CSV:

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

Преимущества:

  • Встроенное обнаружение спецификации
  • Настройка по умолчанию/резервное кодирование настраивается
  • довольно надежный (по моему опыту) для западноевропейских файлов, содержащих некоторые экзотические данные (например, французские имена) со смесью файлов UTF-8 и Latin-1 - в основном основная часть американской и западной европейской сред.

Примечание: Я тот, кто написал этот класс, поэтому, очевидно, возьмите его с солью!:)

Ответ 6

Notepad ++ имеет эту функцию из коробки. Он также поддерживает его изменение.

Ответ 7

В поисках другого решения я обнаружил, что

https://code.google.com/p/ude/

это решение очень тяжелое.

Мне нужно некоторое базовое определение кодировки, основанное на 4 первых байтах и, возможно, обнаружении charset-кода xml, поэтому я взял некоторый образец исходного кода из Интернета и добавил слегка измененную версию

http://lists.w3.org/Archives/Public/www-validator/2002Aug/0084.html

написанный для Java.

    public static Encoding DetectEncoding(byte[] fileContent)
    {
        if (fileContent == null)
            throw new ArgumentNullException();

        if (fileContent.Length < 2)
            return Encoding.ASCII;      // Default fallback

        if (fileContent[0] == 0xff
            && fileContent[1] == 0xfe
            && (fileContent.Length < 4
                || fileContent[2] != 0
                || fileContent[3] != 0
                )
            )
            return Encoding.Unicode;

        if (fileContent[0] == 0xfe
            && fileContent[1] == 0xff
            )
            return Encoding.BigEndianUnicode;

        if (fileContent.Length < 3)
            return null;

        if (fileContent[0] == 0xef && fileContent[1] == 0xbb && fileContent[2] == 0xbf)
            return Encoding.UTF8;

        if (fileContent[0] == 0x2b && fileContent[1] == 0x2f && fileContent[2] == 0x76)
            return Encoding.UTF7;

        if (fileContent.Length < 4)
            return null;

        if (fileContent[0] == 0xff && fileContent[1] == 0xfe && fileContent[2] == 0 && fileContent[3] == 0)
            return Encoding.UTF32;

        if (fileContent[0] == 0 && fileContent[1] == 0 && fileContent[2] == 0xfe && fileContent[3] == 0xff)
            return Encoding.GetEncoding(12001);

        String probe;
        int len = fileContent.Length;

        if( fileContent.Length >= 128 ) len = 128;
        probe = Encoding.ASCII.GetString(fileContent, 0, len);

        MatchCollection mc = Regex.Matches(probe, "^<\\?xml[^<>]*encoding[ \\t\\n\\r]?=[\\t\\n\\r]?['\"]([A-Za-z]([A-Za-z0-9._]|-)*)", RegexOptions.Singleline);
        // Add '[0].Groups[1].Value' to the end to test regex

        if( mc.Count == 1 && mc[0].Groups.Count >= 2 )
        {
            // Typically picks up 'UTF-8' string
            Encoding enc = null;

            try {
                enc = Encoding.GetEncoding( mc[0].Groups[1].Value );
            }catch (Exception ) { }

            if( enc != null )
                return enc;
        }

        return Encoding.ASCII;      // Default fallback
    }

Достаточно прочитать первые 1024 байта из файла, но я загружаю весь файл.

Ответ 8

Я сделал что-то подобное в Python. В принципе, вам нужно много выборочных данных из разных кодировок, которые разбиваются на скользящее двухбайтовое окно и хранятся в словаре (хэш), на основе байтовых пар, предоставляющих значения списков кодировок.

Учитывая этот словарь (хэш), вы берете текст ввода и:

  • если он начинается с любого символа спецификации ('\ xfe\xff' для UTF-16-BE, '\ xff\xfe' для UTF-16-LE, '\ xef\xbb\xbf' для UTF-8 и т.д.), Я рассматриваю его как предложенный
  • если нет, то возьмите достаточно большой образец текста, возьмите все байтовые пары образца и выберите кодировку, которая является наименее распространенной из словаря.

Если вы также выбрали UTF-кодированные тексты, которые не запускаются с какой-либо спецификацией, второй шаг будет охватывать те, которые проскальзывали с первого шага.

Пока это работает для меня (образцы данных и последующие входные данные являются субтитрами на разных языках) с уменьшением частоты ошибок.

Ответ 9

Если кто-то ищет решение на 93,9%. Это работает для меня:

public static class StreamExtension
{
    /// <summary>
    /// Convert the content to a string.
    /// </summary>
    /// <param name="stream">The stream.</param>
    /// <returns></returns>
    public static string ReadAsString(this Stream stream)
    {
        var startPosition = stream.Position;
        try
        {
            // 1. Check for a BOM
            // 2. or try with UTF-8. The most (86.3%) used encoding. Visit: http://w3techs.com/technologies/overview/character_encoding/all/
            var streamReader = new StreamReader(stream, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true), detectEncodingFromByteOrderMarks: true);
            return streamReader.ReadToEnd();
        }
        catch (DecoderFallbackException ex)
        {
            stream.Position = startPosition;

            // 3. The second most (6.7%) used encoding is ISO-8859-1. So use Windows-1252 (0.9%, also know as ANSI), which is a superset of ISO-8859-1.
            var streamReader = new StreamReader(stream, Encoding.GetEncoding(1252));
            return streamReader.ReadToEnd();
        }
    }
}

Ответ 10

Конструктор класса StreamReader принимает параметр "обнаружить кодирование".

Ответ 11

Инструмент "uchardet" делает это хорошо, используя модели распределения частоты символов для каждой кодировки. Большие файлы и более "типичные" файлы имеют большую уверенность (очевидно).

На ubuntu вы просто apt-get install uchardet.

В других системах получите источник, использование и документы здесь: https://github.com/BYVoid/uchardet

Ответ 12

Если вы можете подключиться к библиотеке C, вы можете использовать libenca. См. http://cihar.com/software/enca/. На странице man:

Enca считывает заданные текстовые файлы или стандартный ввод, если ни один не указан, и использует знания об их языке (должен поддерживаться вами) и смесь парсинга, статистического анализа, угадывания и черной магии для определения их кодировок.

Это GPL v2.

Ответ 13

Получил ту же проблему, но не нашел хорошего решения, но обнаружил его автоматически. Теперь я использую PsPad (www.pspad.com) для этого;) Хорошо работает

Ответ 14

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

Большинство людей (или приложений) делают вещи практически в одном и том же порядке каждый раз, часто на одной машине, поэтому вполне вероятно, что когда Боб создает файл .csv и отправляет его в Mary, он всегда будет использовать Windows -1252 или независимо от того, на что его машина по умолчанию.

По возможности немного тренировок клиентов никогда не повредит: -)

Ответ 15

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

Итак, где я впервые делал: Файл StreamReader = File.OpenText(fullfilename);

Мне пришлось изменить его на: Файл StreamReader = новый StreamReader (fullfilename, System.Text.Encoding.UTF7);

OpenText предполагает UTF-8.

вы также можете создать StreamReader, как это новый StreamReader (fullfilename, true), второй параметр означает, что он должен попытаться обнаружить кодировку из byteordermark файла, но это не сработало в моем случае.

Ответ 16

Как аддон к сообщению ITmeze, я использовал эту функцию для преобразования вывода порта С# для универсального детектора Charset Mozilla

    private Encoding GetEncodingFromString(string encoding)
    {
        try
        {
            return Encoding.GetEncoding(encoding);
        }
        catch
        {
            return Encoding.ASCII;
        }
    }

MSDN

Ответ 17

Откройте файл в AkelPad (или просто скопируйте/вставьте искаженный текст), перейдите в Edit → Selection → Recode... → установите флажок "Autodetect".

Ответ 18

Я использую этот код для обнаружения Unicode и кодовой страницы ansi по умолчанию Windows при чтении файла. Для других кодировок необходима проверка содержимого, вручную или путем программирования. Это может использоваться для сохранения текста с той же кодировкой, что и при его открытии. (Я использую VB.NET)

'Works for Default and unicode (auto detect)
Dim mystreamreader As New StreamReader(LocalFileName, Encoding.Default) 
MyEditTextBox.Text = mystreamreader.ReadToEnd()
Debug.Print(mystreamreader.CurrentEncoding.CodePage) 'Autodetected encoding
mystreamreader.Close()