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

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

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

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


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

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

устранение:

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

20 ответов


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

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

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

Самый Важный Факт О Кодировках

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

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


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


ты пробовал C# порт для 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.");
        }
    }
}    

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

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

учитывая разумное количество текста, можно даже определить язык.

вот еще один Я только что нашел с помощью Google:


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

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

плюсы:

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

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


Notepad++ не имеет такой возможности из-из-коробки. Он также поддерживает его изменение.


ища другое решение, я обнаружил, что

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

это решение тяжеловато.

Мне нужно было базовое обнаружение кодировки, основанное на 4 первых байтах и, вероятно, обнаружение кодировки 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 байта из файла, но я загружаю весь файл.


Если кто-то ищет 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();
        }
    }
}

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

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

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

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

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


конструктор класса StreamReader принимает параметр' detect encoding'.


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

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

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


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

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

это GPL v2.


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


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

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

там, где это возможно, немного обучения клиентов никогда не повредит либо :-)


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

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

Мне пришлось изменить его на: Файл поток streamreader = новый поток streamreader(fullfilename, системы.Текст.Кодирование.UTF7);

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

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


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


в качестве дополнения к itmeze post я использовал эту функцию для преобразования вывода порта C# для универсального детектора кодировок Mozilla

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

MSDN


спасибо @Ерик Aronesty указать uchardet.

Между тем (то же самое?) инструмент существует для Linux: chardet.
Или, на cygwin вы можете использовать:chardetect.

посмотреть: chardet man page: https://www.commandlinux.com/man-page/man1/chardetect.1.html

это эвристически обнаружит (угадает) кодировку символов для каждого данного файла и сообщит имя и уровень доверия для каждого файла обнаружены кодировки.


10Y (!) прошло с тех пор, как это было задано, и до сих пор я не вижу упоминания о хорошем, не-GPL'Ed решении MS: IMultiLanguage2 API-интерфейс.

большинство библиотек, уже упомянутых, основаны на UDE Mozilla - и кажется разумным, что браузеры уже решали аналогичные проблемы. Я не знаю, что такое решение chrome, но с IE 5.0 MS выпустили их, и это:

  1. без проблем лицензирования GPL-и-подобных,
  2. резервные и поддерживается, вероятно, навсегда,
  3. дает богатый выход-все действительные кандидаты для кодирования / кодовых страниц вместе с оценками доверия,
  4. удивительно простой в использовании (это один вызов функции).

Это родной вызов COM, но вот некоторые очень хорошие работы Карстен Цоймер, который обрабатывает беспорядок взаимодействия для использования .net. Есть и другие, но по большому счету эта библиотека не получает того внимания, которого заслуживает.


Я использую этот код для обнаружения кодовой страницы Unicode и windows по умолчанию ansi при чтении файла. Для других кодировок необходима проверка содержимого вручную или путем программирования. Это может использоваться для сохранения текста с той же кодировкой, что и при его открытии. (Я использую 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()