Encoding utf 8 python что это
Работаем с текстами на Python: кодировки, нормализация, чистка
Зачем эта статья?
Об обработке текстов на естественном языке сейчас знают все. Все хоть раз пробовали задавать вопрос Сири или Алисе, пользовались Grammarly (это не реклама), пробовали генераторы стихов, текстов. или просто вводили запрос в Google. Да, вот так просто. На самом деле Google понимает, что вы от него хотите, благодаря штукам, которые умеют обрабатывать и анализировать естественную речь в вашем запросе.
При анализе текста мы можем столкнуться с ситуациями, когда текст содержит специфические символы, которые необходимо проанализировать наравне с «простым текстом» (взять даже наши горячо любимые вставки на французском из «Война и мир») или формулы, например. В таком случае обработка текста может усложниться.
Вы можете заметить, что если ввести в поисковую строку запрос с символами с ударением (так называемый модифицирующий акут), к примеру «ó», поисковая система может показать результаты, содержащие слова из вашего запроса, символы с ударением уже выглядят как обычные символы.
Обратите внимание на следующий запрос:
Запрос содержит символ с модифицирующим акутом, однако во втором результате мы можем заметить, что выделено найденное слово из запроса, только вот оно не содержит вышеупомянутый символ, просто букву «о».
Конечно, уже есть много готовых инструментов, которые довольно неплохо справляются с обработкой текстов и могут делать разные крутые вещи, но я не об этом хочу вам поведать. Я не буду рассказывать про nltk, стемминг, лемматизацию и т.п. Я хочу опуститься на несколько ступенек ниже и обсудить некоторые тонкости кодировок, байтов, их обработки.
Откуда взялась статья?
Одним из важных составляющих в области ИИ является обработка текстов на естественном языке. В процессе изучения данной тематики я начал задавать себе вопросы, которые в конечном итоге привели меня к изучению кодировок, представлению текстов в памяти, как они преобразуются, приводятся к нормальной форме. Я плохо понимал эту тему в начале, потребовалось немало времени и мозгового ресурса, чтобы понять, принять и запомнить некоторые вещи. Написанием данной статьи я хочу облегчить жизнь людям, которые столкнутся с необходимостью чтения и обработки текстов на Python и самому закрепить изученное. А некоторыми полезными поинтами своего изучения я постараюсь поделиться в данной статье.
Важная ремарка: я не являюсь специалистом в области обработки текстов. Изложенный материал является результатом исключительно любительского изучения.
Проблема чтения файлов
Допустим, у нас есть файл с текстом. Нам нужно этот текст прочитать. Казалось бы, пиши себе такой вот скрипт для чтения из файла да и радуйся:
В файле содержится вот такое вот изречение:
что переводится с испанского как питон. Однако консоль OC Windows 10 покажет нам немного другой результат:
Сейчас мы разберёмся, что именно пошло не так и по какой причине.
Кодировка
Думаю, это не будет сюрпризом, если я скажу, что любой символ, который заносится в память компьютера, хранится в виде числа, а не в виде литерала. Это число определяется как идентификатор или кодовая позиция символа. Кодировка определяет, какое именно число будет ассоциировано с символом.
Предположим, у нас есть некоторый файл с неизвестным содержимым, и нам нужно его прочитать, однако мы не знаем, какая у файла кодировка. Попробуем декодировать содержимое файла.
Посмотрим на результат:
Важный поинт: при записи и чтении из файлов следует указывать конкретную кодировку, это позволит избежать путаницы в дальнейшем.
Ошибки, связанные с кодировками
При возникновении ошибки, связанной с кодировками, интерпретатор выдаст одно из следующих исключений:
Попытка выполнения вот такого кода (в файле всё ещё содержится испанский питон):
даст нам следующий результат:
Обозначение
Суть
Значение по умолчанию. Несоотвествующие кодировке символы возбуждают исключения UnicodeError и наследуемые от него.
Несоответсвующие символы пропускаются без возбуждения исключений.
Только для метода encode :
Несоответствующие символы заменяются на соответсвующие значения XML.
Несоответствующие символы заменяются на определённые последовательности с обратным слэшем.
Несоответствующие символы заменяются на имена этих символов, которые берутся из базы данных Unicode.
Приведём пример использования таких обработчиков:
Важный поинт: если в текстах могут встретиться неожиданные для кодировки символы, во избежание возбуждения исключений можно использовать обработчики.
Cворачивание регистра
И по классике приведём пример:
В результате применённый метод не только привёл весь текст к нижнему регистру, но и преобразовал специфический немецкий символ.
Нормализация
Чтобы обозначить важность нормализации, приведём простой пример:
Внешне два этих символа выглядят абсолютно одинаково. Однако если мы попытаемся вывести имена этих символов, как их видит интерпретатор Python’a, результат нас порядком удивит.
В Python есть отличный встроенный модуль, который содержит данные о символах Unicode, их имена, являются ли они цифрамии и т.п. (методы по типу str.isdigit() берут информацию из этих данных). Воспользуемся данным модулем, чтобы вывести имена символов, исходя из информации, которая содержится в базе данных Unicode.
Результат выполнения данного кода:
Итак, интерпретатор Python’a видит эти символы как два разных, но в стандарте Unicode они имеют одинаковое отображение.Такие символы называют каноническими эквивалентами. Приложения будут считать два этих символа одинаковыми, но не интерпретатор.
Посмотрим на ещё один пример:
Данные символы также будут являться каноническими эквивалентами. Из примера мы видим, что символ «é» в стандарте Unicodeможет быть представлен двумя способами, которые к тому же имеют разную длину. Символ «é» может быть представлен одним или двумя байтами.
codecs — Реестр кодировок и базовых классов¶
Исходный код: Lib/codecs.py
Модуль определяет следующие функции для кодирования и декодирования с помощью любой кодировки:
codecs. encode ( obj, encoding=’utf-8′, errors=’strict’ ) ¶
Кодирует obj с использованием кодировки, зарегистрированной для encoding.
codecs. decode ( obj, encoding=’utf-8′, errors=’strict’ ) ¶
Декодирует obj с использованием кодировки, зарегистрированной для encoding.
Полную информацию о каждой кодировке также можно посмотреть напрямую:
codecs. lookup ( encoding ) ¶
class codecs. CodecInfo ( encode, decode, streamreader=None, streamwriter=None, incrementalencoder=None, incrementaldecoder=None, name=None ) ¶
Сведения о кодировке при поиске в реестре кодировок. Аргументы конструктора хранятся в одноименных атрибутах:
Классы инкрементального кодера и декодера или функции фабрики. Они должны предоставлять интерфейс, определенный базовыми классами IncrementalEncoder и IncrementalDecoder соответственно. Дополнительные кодировки могут сохранять состояние.
Классы записи и чтения потоков или функции фабрики. Они должны обеспечивать интерфейс, определенный базовыми классами StreamWriter и StreamReader соответственно. Кодировки потока могут поддерживать состояние.
Чтобы упростить доступ к различным компонентам кодировок, модуль предоставляет следующие дополнительные функции, которые используют lookup() для поиска кодировок:
codecs. getencoder ( encoding ) ¶
Найти кодек для данной кодировки и вернуть её функцию кодировки.
Вызывает LookupError в случае, если кодировка не может быть найдена.
codecs. getdecoder ( encoding ) ¶
Найти кодек для данной кодировки и вернуть её функцию декодирования.
Вызывает LookupError в случае, если кодировка не может быть найдена.
codecs. getincrementalencoder ( encoding ) ¶
Найти кодек для данной кодировки и вернуть её класс инкрементального кодера или функцию фабрику.
Вызывает LookupError в случае, если кодировка не может быть найдена или кодек не поддерживает инкрементный кодер.
codecs. getincrementaldecoder ( encoding ) ¶
Найти кодек для данной кодировки и вернуть его класс инкрементного декодера или функцию фабрику.
Вызывает LookupError в случае, если кодировка не может быть найдена или кодек не поддерживает инкрементный декодер.
codecs. getreader ( encoding ) ¶
Найти кодек для данной кодировки и вернуть его класс StreamReader или функцию фабрику.
Вызывает LookupError в случае, если кодировка не может быть найдена.
codecs. getwriter ( encoding ) ¶
Найти кодек для данной кодировки и вернуть его класс StreamWriter или функцию фабрику.
Вызывает LookupError в случае, если кодировка не может быть найдена.
Пользовательские кодеки становятся доступными после регистрации подходящей функции поиска кодека:
codecs. register ( search_function ) ¶
Поиск функции регистрации в настоящее время необратима, что в некоторых случаях может вызвать проблемы, например, при модульном тестировании или перезагрузке модуля.
Хотя встроенная open() и связанный с ней модуль io являются рекомендуемым подходом для работы с закодированными текстовыми файлами, этот модуль предоставляет дополнительные служебные функции и классы, которые позволяют использовать более широкий диапазон кодеков при работе с двоичными файлами:
codecs. open ( filename, mode=’r’, encoding=None, errors=’strict’, buffering=-1 ) ¶
encoding указывает кодировку, которая будет использоваться для файла. Разрешена любая кодировка, которая кодирует и декодирует из байтов, а типы данных, поддерживаемые файловыми методами, зависят от используемого кодека.
codecs. EncodedFile ( file, data_encoding, file_encoding=None, errors=’strict’ ) ¶
Данные, записанные в обёрнутый файл, декодируются в соответствии с заданным data_encoding, а затем записываются в исходный файл в виде байтов с использованием file_encoding. Байты, считанные из исходного файла, декодируются согласно file_encoding, а результат кодируется с использованием data_encoding.
Если file_encoding не указан, по умолчанию используется data_encoding.
codecs. iterencode ( iterator, encoding, errors=’strict’, **kwargs ) ¶
codecs. iterdecode ( iterator, encoding, errors=’strict’, **kwargs ) ¶
Модуль также предоставляет следующие константы, которые полезны для чтения и записи в файлы, зависящие от платформы:
codecs. BOM ¶ codecs. BOM_BE ¶ codecs. BOM_LE ¶ codecs. BOM_UTF8 ¶ codecs. BOM_UTF16 ¶ codecs. BOM_UTF16_BE ¶ codecs. BOM_UTF16_LE ¶ codecs. BOM_UTF32 ¶ codecs. BOM_UTF32_BE ¶ codecs. BOM_UTF32_LE ¶
Базовые классы кодеков¶
Модуль codecs определяет множество базовых классов, которые определяют интерфейсы для работы с объектами кодеков, а также могут использоваться в качестве основы для пользовательских реализаций кодеков.
Каждый кодек должен определить четыре интерфейса, чтобы его можно было использовать в качестве кодека в Python: кодер без сохранения состояния, декодер без состояния, средство чтения потока и средство записи потока. Средство чтения и записи потока обычно повторно используют кодер/декодер без сохранения состояния для реализации файловых протоколов. Авторам кодировок также необходимо определить, как кодек будет обрабатывать ошибки кодирования и декодирования.
Обработчики ошибок¶
Чтобы упростить и стандартизировать обработку ошибок, кодеки могут реализовывать различные схемы обработки ошибок, принимая строковый аргумент errors. Следующие строковые значения определены и реализованы всеми стандартными кодеками Python:
Следующие ниже обработчики ошибок применимы только к текстовым кодировкам :
Кроме того, следующий обработчик ошибок специфичен для данных кодеков:
Значение | Кодеки | Значение |
---|---|---|
‘surrogatepass’ | utf-8, utf-16, utf-32, utf-16-be, utf-16-le, utf-32-be, utf-32-le | Разрешить кодирование и декодирование суррогатных кодов. Эти кодеки обычно рассматривают присутствие суррогатов как ошибку. |
Изменено в версии 3.4: Обработчики ошибок ‘surrogatepass’ теперь работают с кодеками utf-16* и utf-32*.
Изменено в версии 3.5: Обработчики ошибок ‘backslashreplace’ теперь работают с декодированием и переводом.
Набор допустимых значений можно расширить, зарегистрировав новый именованный обработчик ошибок:
codecs. register_error ( name, error_handler ) ¶
Зарегистрировать функцию обработки ошибок error_handler под именем name. Аргумент error_handler будет вызываться во время кодирования и декодирования в случае ошибки, если в качестве параметра ошибок указано name.
Декодирование и перевод работают аналогично, за исключением того, что UnicodeDecodeError или UnicodeTranslateError будут переданы обработчику, а замена из обработчика ошибок будет помещена в вывод напрямую.
Ранее зарегистрированные обработчики ошибок (включая стандартные обработчики ошибок) можно найти по имени:
codecs. lookup_error ( name ) ¶
Возвращает обработчик ошибок, ранее зарегистрированный под именем name.
Вызывает LookupError в случае, если обработчик не может быть найден.
Следующие стандартные обработчики ошибок также доступны как функции уровня модуля:
codecs. strict_errors ( exception ) ¶
codecs. replace_errors ( exception ) ¶
Реализует обработку ошибок ‘replace’ (только для текстовых кодировок ): заменяет ‘?’ для ошибок кодирования (кодируется кодеком) и ‘\ufffd’ (символ замены Юникод) для ошибок декодирования.
codecs. ignore_errors ( exception ) ¶
Реализует обработку ошибок ‘ignore’ : искаженные данные игнорируются, а кодирование или декодирование продолжается без дальнейшего уведомления.
codecs. xmlcharrefreplace_errors ( exception ) ¶
Реализует обработку ошибок ‘xmlcharrefreplace’ (только для кодирования с текстовыми кодировками ): некодируемый символ заменяется соответствующей ссылкой на XML символ.
codecs. backslashreplace_errors ( exception ) ¶
Реализует обработку ошибок ‘backslashreplace’ (только для текстовых кодировок ): искаженные данные заменяются escape-последовательностью с обратной косой чертой.
codecs. namereplace_errors ( exception ) ¶
Реализует обработку ошибок ‘namereplace’ (только для кодирования с текстовыми кодировками ): некодируемый символ заменяется escape-последовательностью \N <. >.
Добавлено в версии 3.5.
Кодирование и декодирование без сохранения состояния¶
Базовый класс Codec определяет следующие методы, которые также определяют функциональные интерфейсы кодера и декодера без сохранения состояния:
Кодирует объект input и возвращает кортеж (выходной объект, потребляемая длина). Например, кодировка текста преобразует строковый объект в объект байтов, используя определенную кодировку набора символов (например, cp1252 или iso-8859-1 ).
В этой ситуации у кодера должна быть возможность обрабатывать ввод нулевой длины и возвращать пустой объект типа объекта вывода.
Декодирует объект input и возвращает кортеж (выходной объект, использованная длина). Например, для текстовой кодировки при декодировании объект байтов, закодированный с использованием кодировки определенного набора символов, преобразуется в строковый объект.
Для текстовых кодировок и байт в байт кодеков input должен быть байтовым объектом или тем, который предоставляет интерфейс буфера только для чтения — например, буферные объекты и файлы с отображением в память.
В этой ситуации у декодера должна быть возможность обрабатывать ввод нулевой длины и возвращать пустой объект типа объекта вывода.
Инкрементное кодирование и декодирование¶
Классы IncrementalEncoder и IncrementalDecoder предоставляют базовый интерфейс для инкрементного кодирования и декодирования. Кодирование/декодирование входных данных выполняется не одним вызовом функции кодера/декодера без сохранения состояния, а несколькими вызовами метода encode() / decode() инкрементного кодера/декодера. Инкрементальный кодер/декодер отслеживает процесс кодирования/декодирования во время вызовов методов.
Объединенный выход вызовов метода encode() / decode() такой же, как если бы все отдельные входы были объединены в один, и этот вход был закодирован/декодирован с помощью кодера/декодера без сохранения состояния.
Объекты IncrementalEncoder¶
Класс IncrementalEncoder используется для кодирования ввода в несколько шагов. Он определяет следующие методы, которые должены определять каждый инкрементальный кодер, чтобы быть совместимым с реестром кодеков Python.
class codecs. IncrementalEncoder ( errors=’strict’ ) ¶
Все инкрементальные кодеры должны предоставлять этот интерфейс конструктора. Они могут добавлять дополнительные ключевые аргументы, но только те, которые определены здесь, используются реестром кодировок Python.
Возвращает текущее состояние кодера, которое должно быть целым числом. Реализация должна убедиться, что 0 является наиболее распространенным состоянием. (Состояния, которые являются более сложными, чем целые числа, могут быть преобразованы в целое число путём маршалинга/пиклинга состояния и кодирования байтов результирующей строки в целое число.)
Объекты IncrementalDecoder¶
Класс IncrementalDecoder используется для декодирования ввода в несколько этапов. Он определяет следующие методы, которые должны определять каждый инкрементный декодер, чтобы быть совместимым с реестром кодеков Python.
class codecs. IncrementalDecoder ( errors=’strict’ ) ¶
Все инкрементные декодеры должны предоставлять этот интерфейс конструктора. Они могут добавлять дополнительные ключевые аргументы, но только те, которые определены здесь, используются реестром кодеков Python.
Сбросить декодер в исходное состояние.
Кодирование и декодирование потока¶
Классы StreamWriter и StreamReader предоставляют общие рабочие интерфейсы, которые можно очень легко использовать для реализации новых подмодулей кодирования. См. encodings.utf_8 для примера, как это делается.
Объекты StreamWriter¶
Класс StreamWriter является подклассом Codec и определяет следующие методы, которые должен определять каждый модуль записи потока, чтобы быть совместимым с реестром кодеков Python.
class codecs. StreamWriter ( stream, errors=’strict’ ) ¶
Все средства записи потока должны предоставлять этот интерфейс конструктора. Они могут добавлять дополнительные ключевые аргументы, но только те, которые определены здесь, используются реестром кодеков Python.
Аргумент stream должен быть файловым объектом, открытым для записи текста или двоичных данных, в зависимости от конкретного кодека.
StreamWriter может реализовывать различные схемы обработки ошибок, предоставляя ключевой аргумент errors. См. Обработчики ошибок для стандартных обработчиков ошибок, которые может поддерживать базовый кодек потока.
Записывает закодированное содержимое объекта в поток.
Записывает объединенный список строк в поток (возможно, путём повторного использования метода write() ). Стандартные байтовые кодеки не поддерживают этот метод.
Очищает и сбрасывает буферы кодеков, используемые для сохранения состояния.
Вызов этого метода должен гарантировать, что данные на выходе переведены в чистое состояние, которое позволяет добавлять новые свежие данные без необходимости повторного сканирования всего потока для восстановления состояния.
Помимо вышеуказанных методов, StreamWriter также должен наследовать все другие методы и атрибуты из базового потока.
Объекты StreamReader¶
Класс StreamReader является подклассом Codec и определяет следующие методы, которые должны определять каждый считыватель потоков для обеспечения совместимости с реестром кодеков Python.
class codecs. StreamReader ( stream, errors=’strict’ ) ¶
Все считыватели потока должны предоставлять этот интерфейс конструктора. Они могут добавлять дополнительные ключевые аргументы, но только те, которые определены здесь, используются реестром кодеков Python.
Аргумент stream должен быть файловым объектом, открытым для чтения текста или двоичных данных, в зависимости от конкретного кодека.
StreamReader может реализовывать различные схемы обработки ошибок, предоставляя ключевой аргумент errors. См. Обработчики ошибок для стандартных обработчиков ошибок, которые может поддерживать базовый потоковый кодек.
Декодирует данные из потока и возвращает получившийся объект.
Аргумент chars указывает количество возвращаемых декодированных кодовых точек или байтов. Метод read() никогда не вернёт больше данных, чем запрошено, но может вернуть меньше, если их недостаточно.
Флаг firstline указывает, что было бы достаточно вернуть только первую строку, если есть ошибки декодирования на более поздних строках.
Метод должен использовать жадную стратегию чтения, означающую, что он должен читать столько данных, сколько разрешено в рамках определения кодировки и заданного размера, например если в потоке доступны необязательные окончания кодирования или маркеры состояния, их также следует прочитать.
Прочтать одну строку из входного потока и вернуть декодированные данные.
size, если он задан, передаётся как аргумент размера методу read() потока.
Если keepends ложно, окончание строки будет удалено из возвращаемых строк.
Прочитать все строки, доступные во входном потоке, и вернуть их в виде списка строк.
Окончания строк реализуются с использованием метода кодировки decode() и включаются в записи списка, если keepends истинно.
Если задан sizehint, передаётся как аргумент size методу read() потока.
Сбрасывает буферы кодека, используемые для сохранения состояния.
Обратите внимание, что изменение положения потока выполняться не должно. Этот метод в первую очередь предназначен для восстановления после ошибок декодирования.
Помимо вышеуказанных методов, StreamReader также должен наследовать все другие методы и атрибуты из базового потока.
Объекты StreamReaderWriter¶
StreamReaderWriter — это удобный класс, который позволяет обёртывать потоки, которые работают как в режиме чтения, так и в режиме записи.
class codecs. StreamReaderWriter ( stream, Reader, Writer, errors=’strict’ ) ¶
Объекты StreamRecoder¶
StreamRecoder переводит данные из одной кодировки в другую, что иногда полезно при работе с разными средами кодирования.
class codecs. StreamRecoder ( stream, encode, decode, Reader, Writer, errors=’strict’ ) ¶
Вы можете использовать эти объекты для прозрачного перекодирования, например, из Latin-1 в UTF-8 и обратно.
Аргумент stream должен быть файловым объектом.
Обработка ошибок выполняется так же, как определено для средств чтения и записи потока.
Кодировки и Юникод¶
Диапазон | Кодировка |
---|---|
U-00000000 … U-0000007F | 0xxxxxxx |
U-00000080 … U-000007FF | 110xxxxx 10xxxxxx |
U-00000800 … U-0000FFFF | 1110xxxx 10xxxxxx 10xxxxxx |
U-00010000 … U-0010FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
Наименьший значащий бит символа Юникода — это крайний правый бит x.
Стандартные кодировки¶
Изменено в версии 3.6: Признана возможность оптимизации для us-ascii.
Многие наборы символов поддерживают одни и те же языки. Они различаются отдельными символами (например, поддерживается ли ЗНАК ЕВРО или нет) и назначением символов кодовым позициям. В частности, для европейских языков обычно существуют следующие варианты:
Добавлено в версии 3.4.
Добавлено в версии 3.4.
Добавлено в версии 3.5.
Добавлено в версии 3.5.
Изменено в версии 3.4: Кодировки utf-16* и utf-32* больше не позволяют кодировать суррогатные кодовые точки ( U+D800 — U+DFFF ). Декодеры utf-32* больше не декодируют байтовые последовательности, соответствующие суррогатным кодовым точкам.
Специальные кодировки Python¶
Ряд предопределённых кодеков специфичен для Python, поэтому их имена не имеют значения за пределами Python. Они перечислены в таблицах ниже на основе ожидаемых типов ввода и вывода (обратите внимание, что, хотя текстовые кодировки являются наиболее распространенным вариантом использования кодеков, базовая инфраструктура кодеков поддерживает произвольные преобразования данных, а не только текстовые кодировки). Для асимметричных кодеков указанное значение описывает направление кодирования.
Текстовые кодировки¶
Только для Windows: кодирующий операнд в соответствии с кодовой страницей OEM (CP_OEMCP).
Добавлено в версии 3.6.
Изменено в версии 3.8: Кодек unicode_internal удалён.