Как определить кодировку файла Python

Обновлено: 06.07.2024

Модуль Python для обнаружения следующих кодировок текстового файла:

Будет проверять файлы UTF-8/16 как с меткой порядка байтов (BOM), так и без нее.

Модуль encdect.py предоставляет один класс EncodingDetectFile и метод load():

  • При успешном обнаружении возвращается кортеж из (encoding,bom_marker,file_unicode) .
  • Ошибка (невозможно определить) возвращает False .

Обновление текстового файла с сохранением кодировки/спецификации (при наличии):

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

Обзор шагов обнаружения в порядке проверки:

Знак порядка байтов (BOM)

Ищет метку порядка следования байтов в первых 2-3 байтах файла в следующем порядке:

  • UTF-16BE (2 байта)
  • UTF-16LE (2 байта)
  • UTF-8 (3 байта, довольно редко)

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

Если спецификация не найдена, определите, является ли файл ASCII или UTF-8:

  • Один байт, прочитанный из файла.
  • Значение определяет, сколько дополнительных байт определяет символ:
    • 1 -> 127 без дополнительных (ASCII).
    • 194 -> 223 1 дополнительный.
    • 224 -> 239 2 дополнительных.
    • 240 -> 244 3 дополнительных.

    Если достигнут конец файла и указанные выше правила остаются в силе:

    • Со всеми байтами в диапазоне от 1 до 127 результат ASCII.
    • Еще результат UTF-8 .

    Если правила не соблюдены, перейти к следующему обнаружению.

    Последний шаг для обнаружения UTF-16 включает два метода.

    Символы конца строки (EOL) ( \r\n ) учитываются в нечетных/четных позициях файлового потока:

    • Если все символы EOL находятся в четных позициях файла, возвращается результат UTF-16BE .
    • В качестве альтернативы, если все символы EOL находятся в нечетных позициях файла, возвращается результат UTF-16LE .

    Исходя из того факта, что текстовые файлы обычно имеют высокое соотношение символов в диапазоне 1 -> 127, двухбайтовые последовательности [0,1 -> 127] или [1 -> 127,0] должны быть распространены:

    Недавнее обсуждение в списке рассылки python-ideas показало, что нам (то есть основным разработчикам Python) необходимо предоставить более четкое руководство о том, как обрабатывать задачи обработки текста, которые по умолчанию вызывают исключения в Python 3, но ранее заметен под ковер беспечным предположением Python 2 о том, что все файлы закодированы в «latin-1».

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

    Что изменилось в Python 3?¶

    Очевидный вопрос: что изменилось в Python 3, так что распространенные подходы, которые разработчики использовали для обработки текста в Python 2, теперь начали выдавать ошибки UnicodeDecodeError и UnicodeEncodeError в Python 3.

    Основное отличие заключается в том, что поведение обработки текста по умолчанию в Python 3 направлено на обнаружение проблем с кодировкой текста как можно раньше — либо при чтении неправильно закодированного текста (обозначается UnicodeDecodeError ), либо при запросе на запись текстовой последовательности, которая не может быть быть правильно представлены в целевой кодировке (обозначается UnicodeEncodeError ).

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

    Тем не менее, Python 3 предоставляет ряд механизмов для ослабления строгих проверок по умолчанию, чтобы обрабатывать различные варианты использования обработки текста (в частности, случаи использования, когда обработка «наилучших усилий» приемлема, а строгая правильность не требуется). . В этой статье мы попытаемся объяснить некоторые из них, рассмотрев случаи, когда их можно было бы использовать.

    Обратите внимание, что многие функции, которые я обсуждаю ниже, также доступны в Python 2, но вы должны получить к ним явный доступ через тип unicode и модуль codecs. В Python 3 они являются частью поведения типа str и встроенной функции open.

    Основы Юникода¶

    Чтобы эффективно обрабатывать текст в Python 3, необходимо хотя бы немного узнать о Unicode и кодировках текста:

    Обработчики ошибок Unicode¶

    Чтобы помочь стандартизировать различные методы обработки ошибок кодирования и декодирования Unicode, Python включает концепцию обработчиков ошибок Unicode, которые автоматически вызываются при возникновении проблемы в процессе кодирования или декодирования текста.

    Я не буду описывать их все в этой статье, но три из них имеют особое значение:

    • strict : это обработчик ошибок по умолчанию, который просто вызывает UnicodeDecodeError при проблемах с декодированием и UnicodeEncodeError при проблемах с кодированием.
    • surrogateescape : это обработчик ошибок, который Python использует для большинства API-интерфейсов ОС, чтобы изящно справляться с проблемами кодирования в данных, предоставляемых ОС. Он обрабатывает ошибки декодирования, помещая данные в малоиспользуемую часть пространства кодовых точек Unicode (для тех, кто интересуется более подробно, см. PEP 383). При кодировании он переводит эти скрытые значения обратно в точную исходную последовательность байтов, которую не удалось правильно декодировать. Подобно тому, как это полезно для API ОС, это может упростить изящную обработку проблем кодирования в других контекстах.
    • backslashreplace : это обработчик ошибок кодирования, который преобразует кодовые точки, которые не могут быть представлены в целевой кодировке, в эквивалентную числовую escape-последовательность строки Python. Это позволяет легко гарантировать, что UnicodeEncodeError никогда не будет выброшен, но при этом не потеряется много информации (поскольку мы не хотим, чтобы проблемы с кодированием скрывали вывод ошибок, этот обработчик ошибок включен в sys.stderr по умолчанию).

    Бинарный опцион¶

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

    Однако как для «текстовых данных с неизвестной кодировкой», так и для «текстовых данных с известной кодировкой, но потенциально содержащих ошибки кодирования» часто предпочтительнее привести их в форму, которую можно обрабатывать как текстовые строки. В частности, некоторые API, которые принимают как байты, так и текст, могут быть очень строгими в отношении кодирования принимаемых ими байтов (например, модуль urllib.urlparse принимает только чистые данные ASCII для обработки в виде байтов, но с радостью обработает текстовые строки, содержащие не -кодовые точки ASCII).

    Обработка текстовых файлов¶

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

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

    Файлы в кодировке, совместимой с ASCII, допустимы все усилия¶

    Случай использования: обрабатываемые файлы имеют кодировку, совместимую с ASCII, но вы точно не знаете, какую именно. Все файлы должны обрабатываться без каких-либо исключений, но некоторый риск повреждения данных считается приемлемым (например, сопоставление файлов журналов из нескольких источников, где некоторые ошибки данных допустимы, при условии, что журналы остаются в основном неповрежденными) .

    Подход: используйте кодировку "latin-1" для сопоставления значений байтов непосредственно с первыми 256 кодовыми точками Unicode. Это самый близкий эквивалент, который предлагает Python 3 для разрешающей модели обработки текста Python 2.

    Пример: f = open(fname, encoding="latin-1")

    Хотя кодировку Windows cp1252 также иногда называют "latin-1", она не отображает все возможные значения байтов, поэтому ее необходимо использовать в сочетании с обработчиком ошибок surrogateescape, чтобы она никогда не выдавала UnicodeDecodeError . Кодировка latin-1 в Python реализует ISO_8859-1:1987, который сопоставляет все возможные значения байтов с первыми 256 кодовыми точками Unicode и, таким образом, гарантирует, что ошибки декодирования никогда не возникнут независимо от настроенного обработчика ошибок.

    Последствия:

    • данные не будут повреждены, если их просто прочитать, обработать как текст ASCII и снова записать.
    • никогда не вызовет ошибку UnicodeDecodeError при чтении данных
    • все равно вызовет ошибку UnicodeEncodeError, если кодовые точки выше 0xFF (например, умные кавычки, скопированные из программы обработки текстов) добавляются к текстовой строке до того, как она будет закодирована обратно в байты. Чтобы предотвратить такие ошибки, используйте обработчик ошибок с обратной косой чертой (или один из других обработчиков ошибок, который заменяет кодовые точки Unicode без представления в целевой кодировке последовательностями кодовых точек ASCII).
    • может произойти повреждение данных, если исходные данные имеют кодировку, несовместимую с ASCII (например, UTF-16)
    • может произойти повреждение, если данные записываются с использованием кодировки, отличной от latin-1.
    • повреждение может произойти, если элементы строки, отличные от ASCII, изменены напрямую (например, для кодировки с переменной шириной, такой как UTF-8, которая вместо этого была декодирована как latin-1, разрезание строки в произвольной точке может разделить несколько -байтовый символ на две части)

    Файлы в кодировке, совместимой с ASCII, минимизируют риск повреждения данных¶

    Случай использования: обрабатываемые файлы имеют кодировку, совместимую с ASCII, но вы точно не знаете, какую именно. Все файлы должны обрабатываться без каких-либо исключений, но некоторые ошибки, связанные с Unicode, допустимы, чтобы снизить риск повреждения данных (например, сопоставление файлов журналов из нескольких источников, но желательно более явное уведомление при сопоставлении). данные могут быть повреждены из-за ошибок программирования, которые нарушают принцип обратной записи данных только в исходной кодировке)

    Подход: используйте кодировку ascii с обработчиком ошибок surrogateescape.

    Пример: f = open(fname, encoding="ascii", errors="surrogateescape")

    Последствия:

    • данные не будут повреждены, если их просто прочитать, обработать как текст ASCII и снова записать.
    • никогда не вызовет ошибку UnicodeDecodeError при чтении данных
    • все равно вызовет ошибку UnicodeEncodeError, если кодовые точки выше 0xFF (например, умные кавычки, скопированные из программы обработки текстов) добавляются к текстовой строке до того, как она будет закодирована обратно в байты. Чтобы предотвратить такие ошибки, используйте обработчик ошибок с обратной косой чертой (или один из других обработчиков ошибок, который заменяет кодовые точки Unicode без представления в целевой кодировке последовательностями кодовых точек ASCII).
    • также вызовет ошибку UnicodeEncodeError, если будет предпринята попытка закодировать текстовую строку, содержащую экранированные значения байтов, без включения обработчика ошибок surrogateescape (или еще более терпимого обработчика, такого как обратная косая черта ).
    • некоторые библиотеки обработки Unicode, обеспечивающие правильность последовательности кодовых точек, могут жаловаться на используемый механизм экранирования (я не буду объяснять, что он здесь означает, но фраза «одиночный суррогат» намекает на то, что что-то из этих линии могут возникать — тот факт, что слово «surrogate» также появляется в имени обработчика ошибок, не является совпадением).
    • повреждение данных все еще может произойти, если исходные данные находятся в кодировке, несовместимой с ASCII (например, UTF-16)
    • повреждение данных также возможно, если экранированные части строки изменяются напрямую

    Файлы в стандартной кодировке для конкретной платформы¶

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

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

    Пример: f = open(fname)

    Последствия:

    • При чтении таких файлов может возникнуть ошибка UnicodeDecodeError (если данные на самом деле не в кодировке, возвращаемой locale.getpreferredencoding() )
    • При записи таких файлов может возникнуть ошибка UnicodeEncodeError (при попытке записи кодовых точек, которые не представлены в целевой кодировке).
    • обработчик ошибок surrogateescape можно использовать, чтобы быть более терпимым к ошибкам кодирования, если необходимо приложить все усилия для обработки файлов, содержащих такие ошибки, вместо того, чтобы сразу отклонять их как недопустимые входные данные.

    Файлы в согласованной известной кодировке¶

    Случай использования: файлы, которые нужно обработать, номинально имеют согласованную кодировку, вы заранее знаете точную кодировку, и допустимо отказаться от обработки файлов, которые не закодированы должным образом. Это становится все более и более распространенным явлением, особенно с учетом того, что многие форматы текстовых файлов начинают стандартизироваться с использованием UTF-8 в качестве предпочтительной кодировки текста.

    Подход: открыть файл в текстовом режиме с соответствующей кодировкой

    Пример: f = open(fname, encoding="utf-8")

    Последствия:

    • При чтении таких файлов может возникнуть ошибка UnicodeDecodeError (если данные на самом деле не в указанной кодировке)
    • При записи таких файлов может возникнуть ошибка UnicodeEncodeError (при попытке записи кодовых точек, которые не представлены в целевой кодировке).
    • обработчик ошибок surrogateescape можно использовать, чтобы быть более терпимым к ошибкам кодирования, если необходимо приложить все усилия для обработки файлов, содержащих такие ошибки, вместо того, чтобы сразу отклонять их как недопустимые входные данные.

    Файлы с надежным маркером кодировки¶

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

    Подход: сначала откройте файл в двоичном режиме, чтобы найти маркер кодировки, а затем снова откройте в текстовом режиме с идентифицированной кодировкой.

    Пример: f = tokenize.open(fname) использует маркеры кодирования PEP 263 для определения кодировки исходных файлов Python (по умолчанию используется UTF-8, если маркер кодирования не обнаружен)

    Последствия:

    • может работать с файлами в разных кодировках
    • может по-прежнему вызывать ошибку UnicodeDecodeError, если маркер кодировки неверен
    • при записи таких файлов необходимо убедиться, что маркер установлен правильно
    • даже если это не кодировка по умолчанию, для отдельных файлов все равно можно настроить использование UTF-8 в качестве кодировки, чтобы поддерживать кодировку почти всех кодовых точек Unicode.
    • обработчик ошибок surrogateescape можно использовать, чтобы быть более терпимым к ошибкам кодирования, если необходимо приложить все усилия для обработки файлов, содержащих такие ошибки, вместо того, чтобы сразу отклонять их как недопустимые входные данные.

    © Copyright 2011, Nick Coghlan, редакция 2fb5e696.

    Версии последние Загрузки pdf html epub On Read the Docs Project Home Сборки Бесплатный хостинг документов, предоставляемый Read the Docs.

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

    <Р> Αν έχετε βρεθεί ποτέ αντιμέτωποι με ένα αρχείο κειμένου που περιέχει ακαταλαβίστικους χαρακτήρες, τότε γνωρίζετε ότι -πολλές φορές- είναι αρκετά δύσκολο να αναγνωρίσετε ποια είναι η σωστή κωδικοποίηση των χαρακτήρων.

    К сожалению, chardetect не всегда находит правильную кодировку. Например, у меня был текстовый файл с кодировкой cp737, но chardetect предсказал для этого файла кодировку IBM866 (с низкой достоверностью 0,26). Для этих сложных случаев я написал инструмент, который декодирует одну строку из текстового файла, используя каждую (?) возможную кодировку символов, и сохраняет результаты в новый текстовый файл utf-8 (то же имя файла + расширение «.encodings»). Теперь мы можем визуально проверить этот файл, чтобы определить правильную кодировку.

    Δυστυχώς, όμως, το chardetect δεν βρίσκει πάντα την σωστή κωδικοποίηση. Για παράδειγμα, είχα να αρχείο κειμνου με κωδικοποίηση CP737 αλλά το Chardetect προέβλλεψε μια κωδικοποίηση IBM866 για εκείνο. Για τέτοιες δύσκολες περιπτώσεις, έγραψα ένα εργαλείο το οποίο αποκωδικοποιεί μια γραμμή από ένα αρχείο κειμένου χρησιμοποιώντας όλες (;) τις δυνατές κωδικοποίησεις και αποθηκεύει τα αποτελέσματα σε ένα νέο UTF-8 αρχείο κειμένου (ίδιο όνομα αρχείου + μια κατάληξη».encodings'). Τώρα, μπορούμε να εξετάσουμε οπτικά αυτό το αρχειο και να ανακαλύψουμε τη σωστί κωδο>ικηδο>ικηδο>ικηδο>ικηδο>

    Использование: test_encodings.py имя файла [количество строк для проверки]

    Χρήση: test_encodings.py όνομα_αρχείου [αριθμός γραμμής προς έλεγχο]

    Вывод cat sometextfile.encodings

    Найдя правильную кодировку, мы можем преобразовать наш текстовый файл в другую кодировку с помощью редактора (например, geany) или инструмента командной строки (например, iconv):

    <Р> Έχοντας βρει τη σωστή κωδικοποίηση, μπορούμε να μετατρέψουμε το αρχείο κειμένου μας σε μια διαφορετική κωδικοποίηση χρησιμοποιώντας έναν διορθώτη κειμένου (λ.χ. τον Geany) ή κάποιο εργαλείο της γραμμής εντολών (λ.χ. το Iconv):

    Только ASCII , UTF-8 и кодировки с использованием спецификации ( UTF-7 со спецификацией, UTF-8 со спецификацией, UTF-16 и UTF-32 ) имеют надежные алгоритмы для получения кодировки документа. Для всех других кодировок вы должны доверять эвристике, основанной на статистике.

    8.1. Является ли ASCII?¶

    Проверить, закодирован ли документ в ASCII, просто: проверьте, не установлен ли бит 7 всех байтов ( 0b0xxxxxxx ).

    В Python можно использовать декодер ASCII:

    Используйте функцию Python только для коротких строк, поскольку она декодирует всю строку в память. Для длинных строк лучше использовать алгоритм функции C, потому что он не выделяет памяти.

    8.2. Проверка маркеров спецификации¶

    Если строка начинается с спецификации, кодировка может быть извлечена из спецификации. Но есть проблема с UTF-16-BE и UTF-32-LE: спецификация UTF-32-LE начинается с спецификации UTF-16-LE.

    Пример написанной на C функции для проверки наличия спецификации:

    Для конфликта спецификаций UTF-16-LE/UTF-32-LE: эта функция возвращает "UTF-32-LE", если строка начинается с "\xFF\xFE\x00\x00" , даже если эта строка может декодироваться из UTF-16-LE.

    Пример получения спецификаций из библиотеки кодеков в Python:

    Эта функция отличается от функции C: она возвращает список. Он возвращает ['UTF-32-LE', 'UTF-16-LE'], если строка начинается с b"\xFF\xFE\x00\x00" .

    8.3. UTF-8?¶

    Кодировка UTF-8 добавляет маркеры к каждому байту, поэтому можно написать надежный алгоритм для проверки того, закодирована ли строка байтов в UTF-8.

    Пример строгой функции C для проверки того, закодирована ли строка с помощью UTF-8.Он отклоняет слишком длинные последовательности (например, 0xC0 0x80 ) и суррогатные символы (например, 0xED 0xB2 0x80 , U+DC80).

    В Python можно использовать декодер UTF-8:

    8.4. Библиотеки¶

    PHP имеет встроенную функцию для определения кодировки строки байтов: mb_detect_encoding().

      : Python-версия алгоритма «chardet», реализованная в Mozilla : программа командной строки (написанная на C) для распознавания кодировки входного файла и его типа конца строки : библиотека Ruby для угадывания кодировки документа

    © Copyright 2010–2011, Виктор Стиннер, редакция 99bc2050.

    Версии последние Загрузки pdf html epub On Read the Docs Project Home Сборки Бесплатный хостинг документов, предоставляемый Read the Docs.

    Читайте также: