На работе кажется, что никакая неделя никогда не проходит без какого-либо связанного с кодированием конниции, катастрофы или катастрофы. Обычно проблема возникает у программистов, которые думают, что могут надежно обработать "текстовый" файл без указания кодировки. Но вы не можете.
Итак, было решено отныне запрещать файлы из когда-либо имеющих имена, заканчивающиеся на *.txt
или *.text
. Мысль заключается в том, что эти расширения вводят в заблуждение случайного программиста в унылое самоуспокоение в отношении кодировок, и это приводит к неправильному обращению. Было бы лучше, если бы не было
вообще, потому что по крайней мере тогда вы знаете, что не знаете, что у вас есть.
Однако, мы arent goint, чтобы зайти так далеко. Вместо этого вы должны будете использовать имя файла, которое заканчивается в кодировке. Например, для текстовых файлов это будет нечто вроде 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. И это особенно проблема.
В течение некоторого времени Ive искал способ программно определить, какой из
находится файл, и я не нашел программу или библиотеку, которая может надежно различать три разных 8-битных кодировки. У нас, вероятно, есть более тысячи файлов MacRoman, поэтому любой детекторы кодировки, которые мы используем, должны быть в состоянии вынюхать их. Ничто из того, что я смотрел, не может справиться с трюком. У меня были большие надежды на библиотеку детекторов charset ICU, но она не может работать с MacRoman. Ive также посмотрел на модули, чтобы делать то же самое в Perl и Python, но снова и снова его всегда одна и та же история: нет поддержки для обнаружения MacRoman.
Поэтому я ищу существующую библиотеку или программу, которая надежно определяет, какой из этих пяти кодировок находится в файле и, желательно, больше. В частности, он должен различать три 3-битных кодирования Ive, обозначенных , особенно MacRoman. Файлы содержат более 99% текста на английском языке; есть несколько на других языках, но не так много.
Если его библиотечный код, нашим языковым предпочтением является его наличие в Perl, C, Java или Python и в этом порядке. Если это просто программа, тогда нам действительно не важно, какой язык ее до тех пор, пока он поставляется в полном исходном коде, работает в Unix и полностью не обременен.
У кого-нибудь еще была проблема с zillion устаревшими текстовыми файлами, случайно закодированными? Если да, то как вы пытались ее решить и насколько вы были успешны? Это самый важный аспект моего вопроса, но мне также интересно, думаете ли вы, что поощряющие программисты называть (или переименовывать) свои файлы с фактической кодировкой этих файлов, помогут нам избежать этой проблемы в будущем. Кто-нибудь когда-либо пытался обеспечить это на институциональной основе, и если да, то это было успешным или нет, и почему?
И да, я полностью понимаю, почему никто не может гарантировать определенный ответ, учитывая характер проблемы. Это особенно характерно для небольших файлов, в которых у вас недостаточно данных для продолжения. К счастью, наши файлы редко бывают маленькими. Помимо случайного файла README
, большинство из них находятся в диапазоне от 50 к до 250 тыс., А многие из них больше. Все, что может быть больше, чем на несколько килограммов, гарантировано на английском языке.
Проблемная область - это биомедицинский интеллектуальный анализ текста, поэтому мы иногда имеем дело с обширными и чрезвычайно крупными корпорациями, такими как весь репозиторий PubMedCentrals Open Access. Довольно огромный файл - BioThesaurus 6.0, 5,7 гигабайта. Этот файл особенно раздражает, потому что это почти все UTF-8. Тем не менее, некоторые numbskull пошли и застряли несколько строк в нем, которые, по-моему, в некотором 8-битном кодировании - Microsoft CP1252. Это займет довольно много времени, прежде чем вы отправитесь в путешествие.: (
Во-первых, простые случаи:
Если ваши данные не содержат байтов выше 0x7F, тогда это ASCII. (Или 7-битное кодирование ISO646, но это очень устарело.)
Если ваши данные проверяются как UTF-8, вы можете с уверенностью предположить, что это UTF-8. Из-за строгих правил проверки UTF-8 ложные срабатывания крайне редки.
Единственное различие между этими двумя кодировками состоит в том, что ISO-8859-1 имеет управляющие символы C1, в которых окна-1252 имеют печатаемые символы €, ƒ "... † ‡ ‰ Š <ŒŽ '" "• --~ š > œžŸ. Я видел много файлов, в которых используются фигурные кавычки или тире, но ни один из них не использует символы управления C1. Так что даже не мешайте им, или ISO-8859-1, вместо этого просто обнаруживайте Windows-1252.
Теперь у вас остается только один вопрос.
Это намного сложнее.
Байты 0x81, 0x8D, 0x8F, 0x90, 0x9D не используются в windows-1252. Если они произойдут, тогда предположим, что данными является MacRoman.
В обоих кодировках байты 0xA2 (¢), 0xA3 (E), 0xA9 (), 0xB1 (±), 0xB5 (μ) совпадают. Если это единственные байты, отличные от ASCII, то неважно, выберете ли вы MacRoman или cp1252.
Считайте символы (NOT byte!) в данных, которые, как известно, UTF-8. Определите наиболее часто используемые символы. Затем используйте эти данные, чтобы определить, являются ли символы cp1252 или MacRoman более распространенными.
Например, в поиске, которое я только что выполнил на 100 случайных английских статьях в Википедии, наиболее распространенными не-ASCII-символами являются ·•–é°’èö—
. Исходя из этого факта,
Подсчитайте байты, предлагающие cp1252, и байты, предлагающие MacRoman, и переходите в зависимости от того, что больше всего.
Mozilla nsUniversalDetector (привязки к Perl: Encode::Detect/Encode::Detect::Detector) доказано в миллион раз.
Моя попытка такой эвристики (при условии, что вы исключили ASCII и UTF-8):
Боковое примечание:
Для таких файлов, как источник Java, где нет такой объект существует внутри файла, вы поместите кодировку раньше расширение, например SomeClass-utf8.java
Не делайте этого!!
Компилятор Java ожидает, что имена файлов будут соответствовать именам классов, поэтому переименование файлов приведет к несовместимости исходного кода. Правильнее было бы угадать кодировку, а затем использовать инструмент native2ascii
для преобразования всех символов, отличных от ASCII, в Unicode escape-последовательности.
*.text
файлов.
"Perl, C, Java или Python, и в этом порядке": интересное отношение: -)
"у нас есть хорошая замена знания, если что-то, вероятно, UTF-8": на самом деле вероятность того, что файл, содержащий значимый текст, закодированный в какой-либо другой кодировке, использующей байты с высоким битом, будет успешно декодироваться, поскольку UTF-8 исчезающе мало.
Стратегии UTF-8 (наименее предпочтительный язык):
# 100% Unicode-standard-compliant UTF-8
def utf8_strict(text):
try:
text.decode('utf8')
return True
except UnicodeDecodeError:
return False
# looking for almost all UTF-8 with some junk
def utf8_replace(text):
utext = text.decode('utf8', 'replace')
dodgy_count = utext.count(u'\uFFFD')
return dodgy_count, utext
# further action depends on how large dodgy_count / float(len(utext)) is
# checking for UTF-8 structure but non-compliant
# e.g. encoded surrogates, not minimal length, more than 4 bytes:
# Can be done with a regex, if you need it
Как только вы решили, что это ни ASCII, ни UTF-8:
Извещатели из набора символов Mozilla, о которых я знаю, не поддерживают MacRoman и в любом случае не очень хорошо работают на 8-битных кодировках, особенно на английском языке, потому что AFAICT зависит от проверки, имеет ли смысл декодирование на данном языке, игнорируя знаки пунктуации и основываясь на широком выборе документов на этом языке.
Как отмечали другие, у вас действительно есть только символы с префиксом с высоким битом, чтобы различать cp1252 и macroman. Я бы предложил обучить модель типа Mozilla для ваших собственных документов, а не Шекспира или Хансарда или Библии KJV, и учесть все 256 байт. Я полагаю, что ваши файлы не имеют разметки (HTML, XML и т.д.) В них, что искажает вероятности чего-то шокирующего.
Вы упомянули файлы, которые в основном UTF-8, но не могут декодироваться. Вы также должны быть очень подозрительны:
(1) файлы, которые якобы закодированы в ISO-8859-1, но содержат "управляющие символы" в диапазоне от 0x80 до 0x9F включительно... это настолько распространено, что проект стандарта HTML5 говорит об декодировании ВСЕХ потоков HTML, объявленных как ISO-8859-1 с использованием cp1252.
(2) файлы, которые декодируют ОК как UTF-8, но полученный Юникод содержит "управляющие символы" в диапазоне U + 0080 до U + 009F включительно... это может быть результатом перекодирования cp1252/cp850 (видно, что это происходит! )/etc файлы из "ISO-8859-1" в UTF-8.
Справочная информация. У меня есть проект wet-Sunday-day, чтобы создать на основе Python детектор набора символов, ориентированный на файл (вместо веб-ориентированного), и хорошо работает с 8-битными наборами символов, включая legacy ** n
такие, как cp850 и cp437. Это нигде не было в прайм-тайм. Я заинтересован в подготовке файлов; являются ли ваши файлы ISO-8859-1/cp1252/MacRoman одинаково "необремененными", как вы ожидаете, что любое решение для кода будет?
Как вы обнаружили, нет идеального способа решить эту проблему, потому что без неявных знаний о том, какая кодировка используется файлом, все 8-битные кодировки являются точно такими же: коллекция байтов. Все байты действительны для всех 8-битных кодировок.
Лучшее, на что вы можете надеяться, - это какой-то алгоритм, который анализирует байты, и на основе вероятностей определенного байта, используемого на определенном языке с определенной кодировкой, угадает, в какой кодировке используются файлы. Но это должно знать, какой язык использует файл, и становится совершенно бесполезным, когда у вас есть файлы со смешанными кодировками.
В верхней части, если вы знаете, что текст в файле написан на английском языке, тогда вы вряд ли заметите какую-либо разницу в зависимости от того, какую кодировку вы решите использовать для этого файла, так как различия между всеми упомянутыми кодировками все локализованные в частях кодировок, которые указывают символы, которые обычно не используются на английском языке. У вас могут быть некоторые проблемы, когда текст использует специальное форматирование или специальные версии пунктуации (например, CP1252 имеет несколько версий символов кавычек), но для сущности текста проблем не будет.
У кого-нибудь еще была проблема с zillion устаревшими текстовыми файлами, случайно закодированными? Если да, то как вы пытались ее решить и насколько вы были успешны?
В настоящее время я пишу программу, которая переводит файлы в XML. Он должен автоопределять тип каждого файла, что является надмножеством проблемы определения кодировки текстового файла. Для определения кодирования я использую байесовский подход. То есть мой классификационный код вычисляет вероятность (вероятность), что текстовый файл имеет определенную кодировку для всех кодировок, которые он понимает. Затем программа выбирает наиболее вероятный декодер. Байесовский подход работает так для каждой кодировки.
Понятно, что теорема Байеса становится очень простой, если вместо вычисления вероятностей вы вычисляете информационный контент, который является логарифмом коэффициентов: info = log(p / (1.0 - p))
.
Вам нужно будет вычислить начальную априорную вероятность и корреляции, просмотрев корпус файлов, который вы классифицировали вручную.
Если вы можете обнаружить каждую кодировку EXCEPT для макромана, то было бы логично предположить, что те, которые не могут быть расшифрованы, находятся в макромане. Другими словами, просто создайте список файлов, которые невозможно обработать, и обрабатывайте их так, как если бы они были макроманами.
Другим способом сортировки этих файлов будет создание серверной программы, которая позволяет пользователям определять, какая кодировка не искажена. Конечно, это было бы в компании, но с 100 сотрудниками, делающими несколько каждый день, вы будете иметь тысячи файлов, сделанных в кратчайшие сроки.
Наконец, было бы лучше просто преобразовать все существующие файлы в один формат и потребовать, чтобы новые файлы находились в этом формате.