На работе кажется, что ни одна неделя не проходит без каких-либо потасовок, связанных с кодированием, бедствий или катастроф. Проблема обычно исходит от программистов, которые думают, что могут надежно обработать «текстовый» файл без указания кодировки. Но ты не можешь.
Поэтому отныне было решено запретить файлам иметь имена, оканчивающиеся на *.txt
или *.text
. Считается, что эти расширения вводят в заблуждение случайного программиста до тупого самоуспокоения относительно кодирования, а это приводит к неправильной обработке. Было бы лучше вообще не иметь расширения, потому что, по крайней мере, тогда вы знаете, что не знаете, что у вас есть.
Однако мы не собираемся заходить так далеко. Вместо этого вы должны будете использовать имя файла, оканчивающееся на кодировку. Так что для текстовых файлов, например, это было бы что - то вроде README.ascii
, README.latin1
, README.utf8
и т.д.
Для файлов, требующих определенного расширения, если можно указать кодировку внутри самого файла, например, в Perl или Python, вы должны это сделать. Для файлов, таких как исходный код Java, где такие средства не существуют внутри файла, вы поместите кодировку перед расширением, например SomeClass-utf8.java
.
Для вывода настоятельно рекомендуется использовать UTF-8 .
Но для ввода нам нужно выяснить, как работать с тысячами файлов в нашей кодовой базе с именем *.txt
. Мы хотим переименовать их все, чтобы они соответствовали нашему новому стандарту. Но мы не можем рассматривать их всех. Итак, нам нужна библиотека или программа, которые действительно работают.
Они представлены в различных форматах ASCII, ISO-8859-1, UTF-8, Microsoft CP1252 или Apple MacRoman. Несмотря на то, что мы знаем, что можем определить, является ли что-то ASCII, и у нас есть хорошая возможность узнать, вероятно ли что-то в UTF-8, насчет 8-битных кодировок нас не интересует. Поскольку мы работаем в смешанной среде Unix (Solaris, Linux, Darwin) с большинством настольных компьютеров Mac, у нас довольно много надоедливых файлов MacRoman. И это особенно проблема.
Некоторое время я искал способ программно определить, какой из
- ASCII
- ISO-8859-1
- CP1252
- МакРоман
- UTF-8
файл находится внутри, и я не нашел программы или библиотеки, которые могли бы надежно различить эти три различных 8-битных кодировки. У нас, вероятно, есть только более тысячи файлов MacRoman, поэтому какой бы детектор кодировки мы ни использовали, он должен уметь их обнаруживать. Ничего из того, на что я смотрел, не помогло. Я возлагал большие надежды на библиотеку детекторов кодировки ICU , но она не может справиться с MacRoman. Я также смотрел модули, которые делают то же самое как в Perl, так и в Python, но снова и снова это всегда одна и та же история: нет поддержки для обнаружения MacRoman.
Поэтому я ищу существующую библиотеку или программу, которая надежно определяет, в какой из этих пяти кодировок находится файл - и желательно больше. В частности, он должен различать три 3-битные кодировки, которые я процитировал, особенно MacRoman . Файлы содержат более 99% текста на английском языке; есть несколько на других языках, но не много.
Если это код библиотеки, мы предпочитаем, чтобы он был на Perl, C, Java или Python и именно в таком порядке. Если это просто программа, то нам все равно, на каком языке она написана, если она идет в полном исходном коде, работает в Unix и полностью свободна.
У кого-нибудь еще была эта проблема с миллионом старых текстовых файлов, случайно закодированных? Если да, то как вы пытались ее решить и насколько вам это удалось? Это самый важный аспект моего вопроса, но меня также интересует, считаете ли вы, что поощрение программистов называть (или переименовывать) свои файлы с фактической кодировкой, в которой находятся эти файлы, поможет нам избежать проблемы в будущем. Кто-нибудь когда-нибудь пытался добиться этого на институциональной основе, и если да, то было ли это успешным или нет, и почему?
И да, я полностью понимаю, почему нельзя гарантировать однозначный ответ, учитывая характер проблемы. Это особенно касается небольших файлов, где у вас недостаточно данных для продолжения. К счастью, наши файлы редко бывают маленькими. За исключением случайного README
файла, большинство из них имеют размер от 50 до 250 КБ, а многие больше. Все, что превышает несколько килобайт, гарантированно будет на английском языке.
Проблемной областью является биомедицинский анализ текста, поэтому мы иногда имеем дело с обширными и чрезвычайно большими корпусами, такими как все репозитории открытого доступа PubMedCentral. Довольно огромный файл - это BioThesaurus 6.0, размером 5,7 гигабайт. Этот файл особенно раздражает, потому что почти весь он UTF-8. Однако какой-то тупица пошел и засунул в него несколько строк в какой-то 8-битной кодировке - мне кажется, Microsoft CP1252. Прежде чем вы наткнетесь на него, пройдет немало времени. :(
Ответы:
Во-первых, простые случаи:
ASCII
Если ваши данные не содержат байтов выше 0x7F, то это ASCII. (Или 7-битная кодировка ISO646, но она очень устарела.)
UTF-8
Если ваши данные проверяются как UTF-8, вы можете с уверенностью предположить, что это UTF-8. Из-за строгих правил проверки UTF-8 ложные срабатывания крайне редки.
ISO-8859-1 против windows-1252
Единственное различие между этими двумя кодировками состоит в том, что ISO-8859-1 имеет управляющие символы C1, тогда как windows-1252 имеет печатные символы € ‚ƒ„… † ‡ ˆ Š ‹ŒŽ ''« »• –—˜ ™ š› œžŸ. Я видел множество файлов, в которых используются фигурные кавычки или тире, но ни один из них не использует управляющие символы C1. Так что даже не связывайтесь с ними или ISO-8859-1, просто вместо этого обнаруживайте windows-1252.
Остается только один вопрос.
Как отличить MacRoman от cp1252?
Это намного сложнее.
Неопределенные символы
Байты 0x81, 0x8D, 0x8F, 0x90, 0x9D не используются в windows-1252. Если они возникают, предположите, что это данные MacRoman.
Идентичные персонажи
Байты 0xA2 (¢), 0xA3 (£), 0xA9 (©), 0xB1 (±), 0xB5 (µ) совпадают в обеих кодировках. Если это единственные байты, отличные от ASCII, то не имеет значения, выберете ли вы MacRoman или cp1252.
Статистический подход
Считайте частоту символов (НЕ байтов!) В данных, которые вы знаете как UTF-8. Определите наиболее частые символы. Затем используйте эти данные, чтобы определить, какие символы более распространены: cp1252 или MacRoman.
Например, при поиске, который я только что выполнил по 100 случайным английским статьям Википедии, наиболее распространенными являются символы, отличные от ASCII
·•–é°®’èö—
. Исходя из этого факта,Подсчитайте байты, предлагающие cp1252, и байты, предлагающие MacRoman, и выберите тот, который больше.
источник
Mozilla nsUniversalDetector (привязки Perl: Encode :: Detect / Encode :: Detect :: Detector ) многократно доказан.
источник
x-mac-cyrillic
поддерживается,x-mac-hebrew
подробно обсуждается в комментариях,x-mac-anything-else
не упоминается.Моя попытка такой эвристики (при условии, что вы исключили ASCII и UTF-8):
Примечание:
Не делай этого!!
Компилятор Java ожидает, что имена файлов будут соответствовать именам классов, поэтому переименование файлов сделает исходный код некомпилируемым. Правильнее было бы угадать кодировку, а затем использовать
native2ascii
инструмент для преобразования всех символов, отличных от ASCII, в escape-последовательности Unicode .источник
*.text
файлов.«Perl, C, Java или Python, и именно в таком порядке»: интересное отношение :-)
«мы переживаем хорошее изменение знания, вероятно ли что-то UTF-8»: на самом деле вероятность того, что файл, содержащий значимый текст, закодированный в какой-то другой кодировке, которая использует байты с высоким битом, будет успешно декодироваться, как UTF-8, исчезающе мала.
Стратегии UTF-8 (на наименее предпочтительном языке):
Если вы решили, что это не ASCII и не UTF-8:
Известные мне детекторы кодировки Mozilla не поддерживают MacRoman и в любом случае плохо работают с 8-битными кодировками, особенно с английским языком, потому что AFAICT они зависят от проверки того, имеет ли декодирование смысл в данном язык, игнорируя знаки препинания, и основанный на широком выборе документов на этом языке.
Как отмечали другие, у вас действительно есть только символы пунктуации с высоким битом, чтобы различать cp1252 и макроман. Я бы посоветовал обучить модель типа Mozilla на ваших собственных документах, а не на Шекспире, Хансарде или Библии KJV, и принять во внимание все 256 байтов. Я предполагаю, что в ваших файлах нет разметки (HTML, XML и т. Д.) - это исказит вероятность чего-то шокирующего.
Вы упомянули файлы, которые в основном имеют формат UTF-8, но не могут декодироваться. Вы также должны очень подозрительно относиться к:
(1) файлы, которые якобы закодированы в ISO-8859-1, но содержат «управляющие символы» в диапазоне от 0x80 до 0x9F включительно ... это настолько распространено, что проект стандарта HTML5 говорит о декодировании ВСЕХ потоков HTML, объявленных как ISO-8859 -1, используя cp1252.
(2) файлы, которые декодируют OK как UTF-8, но результирующий Unicode содержит «управляющие символы» в диапазоне от U + 0080 до U + 009F включительно ... это может быть результатом перекодирования cp1252 / cp850 (это уже было видно!) / И т. Д. файлы из "ISO-8859-1" в UTF-8.
Предыстория: у меня есть проект влажного воскресенья и полудня по созданию детектора кодировки на основе Python, ориентированного на файлы (вместо веб-ориентированного) и хорошо работающего с 8-битными наборами символов, включая
legacy ** n
такие, как cp850 и cp437. Пока еще далеко не прайм-тайм. Меня интересуют учебные файлы; Ваши файлы ISO-8859-1 / cp1252 / MacRoman столь же "необременительны", как вы ожидаете от любого решения для кода?источник
Как вы обнаружили, идеального способа решения этой проблемы не существует, потому что без неявного знания о том, какую кодировку использует файл, все 8-битные кодировки будут одинаковыми: набором байтов. Все байты действительны для всех 8-битных кодировок.
Лучшее, на что вы можете надеяться, - это своего рода алгоритм, который анализирует байты и на основе вероятностей использования определенного байта на определенном языке с определенной кодировкой будет угадывать, какую кодировку используют файлы. Но это должно знать, какой язык использует файл, и становится совершенно бесполезным, когда у вас есть файлы со смешанными кодировками.
С другой стороны, если вы знаете, что текст в файле написан на английском языке, то вы вряд ли заметите какую-либо разницу, какую бы кодировку вы ни выбрали для этого файла, поскольку все различия между всеми упомянутыми кодировками локализованы в части кодировок, которые определяют символы, обычно не используемые в английском языке. У вас могут возникнуть проблемы, когда в тексте используется специальное форматирование или специальные версии знаков препинания (например, CP1252 имеет несколько версий символов кавычек), но для сути текста проблем, вероятно, не будет.
источник
Если вы можете обнаружить каждую кодировку, ЗА ИСКЛЮЧЕНИЕМ для макромана, было бы логично предположить, что те, которые не могут быть расшифрованы, находятся в макроманале. Другими словами, просто составьте список файлов, которые не могут быть обработаны, и обрабатывайте их, как если бы они были макроманами.
Другой способ отсортировать эти файлы - создать серверную программу, позволяющую пользователям решать, какая кодировка не искажена. Конечно, это будет внутри компании, но если 100 сотрудников будут выполнять несколько задач каждый день, тысячи файлов будут созданы в кратчайшие сроки.
Наконец, не лучше ли просто преобразовать все существующие файлы в один формат и потребовать, чтобы новые файлы были в этом формате.
источник
В настоящее время я пишу программу, которая переводит файлы в XML. Он должен автоматически определять тип каждого файла, что является расширением проблемы определения кодировки текстового файла. Для определения кодировки я использую байесовский подход. То есть мой классификационный код вычисляет вероятность (вероятность) того, что текстовый файл имеет определенную кодировку для всех кодировок, которые он понимает. Затем программа выбирает наиболее вероятный декодер. Байесовский подход работает так для каждого кодирования.
Выясняется , что Байеса теорема становится очень легко сделать , если вместо вычисления вероятностей, то вычислить содержание информации , которая является логарифмом шансов :
info = log(p / (1.0 - p))
.Вам нужно будет вычислить исходную априорную вероятность и корреляции, исследуя корпус файлов, которые вы вручную классифицировали.
источник