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


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

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

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


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

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

устранение:

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

20 ответов:

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

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

Специально Джоэль говорит:

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

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

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

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

ты пробовал C# порт для Mozilla Universal Charset Detector

пример из 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-в основном основная часть сред США и Западной Европы.

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

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

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

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) для этого ;) отлично работает

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

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

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

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

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

Мне пришлось изменить его на: StreamReader file = new StreamReader (fullfilename, System.Текст.Кодирование.UTF7);

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

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

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

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

    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()