Как читаются текстовые файлы
В Python текст может быть представлен с использованием строки Юникода или байтов. Юникод считается стандартом кодирования. Строка Unicode — это структура данных Python, которая может хранить ноль или более символов. Она предназначена для хранения текстовых данных. С другой стороны, это просто последовательность байтов, в которой могут храниться произвольные двоичные данные. Когда вы работаете со строками в оперативной памяти, вы можете сделать это только с помощью строки Unicode. Если вам нужно выполнить ввод-вывод, вам понадобится двоичное представление строки. Типичный ввод-вывод включает в себя чтение и запись в консоль, файлы и сетевые сокеты.
Что такое кодировка символов
Кодировки символов — это определенные наборы правил для преобразования необработанных двоичных байтовых строк (они выглядят следующим образом: 0110100001101001) в символы, составляющие удобочитаемый текст (например, «привет»). Существует много разных кодировок, и если вы попытаетесь прочитать текст с кодировкой, отличной от той, в которой он был изначально написан, вы получите зашифрованный текст, называемый «mojibake». Пример:
æ–‡å—化ã??
Можно получить и «неизвестные» знаки. Они возникают, когда нет сопоставления между конкретным байтом и символом в кодировке, которую вы используете для чтения строки байтов. Пример таких знаков:
�����
Популярные кодировки
Чтобы понять, как Python управляет Unicode, необходимо разобраться в обработке символов. Компьютерные файлы записываются с применением определенного набора символов. Набор символов используется в языке или домене. Например, письменный английский язык соответствует набору символов, содержащему 26 букв верхнего и нижнего регистра, а также знаки препинания. Однако компьютеры используют более формальную коллекцию, называемую набором кодированных символов (CCS).
В CCS каждому символу присваивается соответствующее числовое значение, известное как кодовая точка. Набор кодовых точек позволяет системе преобразовывать экранное представление каждого символа в его двоичный эквивалент. Каждый набор символов также связан с кодовой единицей. Кодовая единица определяет размер каждого закодированного символа. Например, набор символов может кодировать каждый символ, используя 16 бит или два байта. Одна и та же кодовая точка может быть связана с разными кодовыми единицами в разных кодировках. Например, значение 127 может быть представлено с использованием 7, 8, 16 или 32 бит. Некоторые форматы даже используют кодировку переменной длины. Это значит, что не получится определить двоичное представление символа на основе его кодовой точки.
Текст декодируется и кодируется с использованием определенного стандарта кодирования. Алгоритм кодирования еще называют codec. Это комбинация кодера и декодера. Система должна знать, какой кодек использовать для правильного кодирования/декодирования файла. Файлы можно декодировать из байтов в символы, а текст можно кодировать из символов в байты. Большинство файлов используют формат кодировки ASCII или Unicode.
ASCII
Существует множество кодировок символов. Одна из самых простых — это ASCII.
Это 7-битная система кодирования символов, которая представляет английские символы с числами от 0 до 127. Она включает числа в диапазоне от 0 до 9, алфавиты верхнего регистра (A-Z), алфавиты нижнего регистра (a-z) и некоторые специальные символы.
Например, буква A представляет номер 65 в системе ASCII, буква Z представляет номер 90. Алфавит нижнего регистра a представлен цифрой 97. Специальные символы, такие как $, обозначаются как 36, @ обозначается как 64 в системе ASCII.
Unicode
Unicode — самый используемый стандарт кодирования. Он был разработан Xerox и Apple, но сейчас администрируется и поддерживается Unicode Consortium. Unicode. Он успешно унифицировал ранее существовавшие наборы символов и теперь служит международным стандартом.
Юникод описывает список доступных символов и их кодовых точек, но не описывает, как сопоставить кодовые точки с байтами. Он также включает формальное имя Unicode для каждого символа. К тексту Юникода можно применять различные схемы кодирования символов (CES) для преобразования символов в байты.
Набор символов Юникода включает все традиционные символы ASCII, международные письменные символы, символы и большое количество смайлов. Unicode также содержит различные управляющие и непечатаемые символы. Каждая буква идентифицируется буквой U, знаком + и ее кодовой точкой. Например, символ, имеющий кодовую точку 639, представлен строкой U+0639.
Кодовое пространство Unicode разделено на семнадцать плоскостей, что помогает структурировать и организовать коллекцию. Связанные символы размещаются внутри смежных блоков внутри одной плоскости. Это упрощает поиск определенных символов в опубликованных таблицах. Все объекты имеют фиксированное имя, которое однозначно идентифицирует их. Это имя невозможно впоследствии изменить, даже если оно неточное или содержит ошибки.
UTF-8
UTF-8 — одна из нескольких схем кодировки символов, реализующих стандарт кодировки Unicode. Схема кодирования преобразует строку в последовательность байтов, а последовательность байтов обратно в строку. UTF-8 определен в RFC 3629. Он способен кодировать все 1 112 064 кодовых точки в Unicode.
UTF-8 обратно совместим с ASCII. Все файлы ASCII совместимы с UTF-8. Файл UTF-8, содержащий только символы ASCII, совместим с системами ASCII.
Единица кода в UTF-8 составляет 8 бит по сравнению с 7 битами в ASCII. Однако один символ может соответствовать от одной до четырех кодовых единиц. Альтернативный кодек UTF-32 представляет все символы с помощью четырех кодовых единиц, каждая из которых состоит из четырех байтов. Это означает, что UTF-8 генерирует файлы гораздо меньшего размера, чем UTF-32.
UTF-8 — самая популярная кодировка в Интернете, она используется на 95–100 % всех веб-сайтов. Сейчас она считается международным стандартом кодировки Unicode. Практически все современные приложения поддерживают UTF-8, а многие стандарты и приложения принимают только файлы в кодировке UTF-8.
UTF-16
UTF-16 — это система кодировки символов, которая использует 16-битный код для кодирования символов.
UTF-16 использует 16-битные кодовые единицы длиной 2 или 4 байта для представления символов. 2-байтовые кодовые единицы используются для представления символов базовой многоязычной плоскости (BMP), которые включают наиболее часто используемые символы. Дополнительные символы или символы, существующие вне BMP, представлены парой 2-байтовых кодовых единиц, известных как суррогатные пары, общим размером 4 байта.
Возможные ошибки, связанные с кодировками
В большинстве случаев процесс кодирования и декодирования проходит хорошо, без дополнительных усилий. Но в Python все же могут возникать ошибки Unicode. Когда Python не может декодировать файл, он отображает сообщение UnicodeDecodeError.
UnicodeError
UnicodeError возникает, когда Python сталкивается с проблемами кодирования или декодирования. Причины этой ошибки:
- конфликты из-за смешанной кодировки в тексте;
- неправильные метки порядка байтов (BOM), приводящие к ошибкам декодирования;
- использование неподдерживаемых или несовпадающих схем кодирования;
- конфликты, возникающие из-за разных стандартов Unicode;
- проблемы с суррогатными парами в UTF-16;
- поврежденные или неполные последовательности байтов.
Пример, где декодирование строки Unicode с помощью ASCII приводит к ошибке:
unicode_str = "\u1234\u5678\u90AB"
decoded_str = unicode_str.encode('utf-8')
print(decoded_str.decode('ascii'))
Traceback (most recent call last):
File "/home/stanley/code_samples/main.py", line 3, in <module>
print(decoded_str.decode('ascii'))
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe1 in position 0: ordinal not in range(128)
Чтобы избежать таких проблем, используйте надежную кодировку, например, UTF-8 и убедитесь, что строки действительны в формате Unicode. Реализация стратегий обработки ошибок, таких как блоки try-except, также может помочь справиться с ошибками кодирования. Обращайте внимание на метки порядка байтов при работе с файлами или потоками данных, а также проверяйте стандарты кодировки и символов внешних источников данных.
UnicodeDecodeError
UnicodeDecodeError возникает, когда кодировка символов читаемых нами байтов и кодировка символов, которую Python пытается использовать для их чтения, не похожи.
Можно использовать метод ignore или replace для удаления специальных символов, которые невозможно закодировать. Вы также можете использовать ignore при открытии файла, чтобы избежать ошибок. Пример:
text = 'ф'
with open('message.txt', 'w', encoding='utf-8', errors='ignore') as f:
f.write(text)
UnicodeEncodeError
Python не может обнаружить символы Юникода и поэтому выдает ошибку кодировки. Он не может закодировать данную строку.
Пример UnicodeEncodeError:
str(u'éducba')
Мы передали аргумент функции str(), который представляет собой строку Unicode. Но эта функция будет использовать процесс кодирования ASCII по умолчанию. Программа выдает ошибку из-за отсутствия спецификации кодировки в начале. По умолчанию используется 7-битная кодировка, которая не может распознавать символы, выходящие за пределы диапазона от 0 до 128. Программу можно исправить, закодировав вручную строку Unicode. Например, encode('utf8'), перед передачей ее функции str().
Работа с системами счисления в Python
Python поддерживает целые числа, числа с плавающей запятой и комплексные числа. В Python они определяются как классы int, float и complex.
- int — содержит целые числа со знаком неограниченной длины;
- float — содержит плавающую десятичную точку и точность до 15 десятичных знаков;
- complex — содержит комплексные числа.
Числа, с которыми мы имеем дело каждый день, относятся к десятичной (по основанию 10) системе счисления. Но программистам приходится работать с двоичной (по основанию 2), шестнадцатеричной (по основанию 16) и восьмеричной (по основанию 8) системами счисления.
В Python мы можем представлять эти числа, помещая соответствующий префикс перед этим числом. Пример:
print(0b1101011) # prints 107
print(0xFB + 0b10) # prints 253
print(0o15) # prints 13
Кодировка Unicode в Python
Строковый тип в Python представляет собой удобочитаемый текст, который может содержать символ Юникода.
С другой стороны, тип данных byte представляет собой двоичные данные, которые не включают кодировку. Кодирование — это процесс преобразования читаемого человеком текста в байты, а декодирование преобразует байтовые данные в читаемый человеком текст.
Python предоставляет методы encode() и decode(), которые по умолчанию принимают «utf-8» в качестве параметра.
>>> "résumé".encode("utf-8")
b'r\xc3\xa9sum\xc3\xa9'
>>> "El Niño".encode("utf-8")
b'El Ni\xc3\xb1o'
>>> b"r\xc3\xa9sum\xc3\xa9".decode("utf-8")
'résumé'
>>> b"El Ni\xc3\xb1o".decode("utf-8")
'El Niño'e
>>> "javatpoint".encode("utf-8")
b'javatpoint'
В приведенном выше фрагменте, метод encode() преобразует résumé в b'r\xc3\xa9sum\xc3\xa9', а представление байтов допускает только символы ASCII.
Подключение Unicode в Python
В Python 3 строки Unicode выражаются как экземпляры встроенного типа Unicode. Внутри Python представляет строки Юникода как 16- или 32-битные целые числа в зависимости от того, как был скомпилирован интерпретатор Python.
Конструктор unicode() имеет подпись unicode(string[,coding,errors]). Все его аргументы должны быть 8-битными строками. Первый аргумент преобразуется в Юникод с использованием указанной кодировки. Если вы опустите аргумент кодировки, для преобразования будет использоваться кодировка ASCII, поэтому символы больше 127 будут рассматриваться как ошибки. Unicode автоматически поддерживается Python. Дополнительно ничего подключать не нужно.
Кодирование и декодирование в Python
Процесс преобразования строк (текста) в компьютерные байты называется кодированием. В Python 3 строки — это текст, который представляет собой символы Юникода. Unicode — это не кодировка, а абстрактный стандарт кодирования, который использует для кодирования формат преобразования Unicode (UTF). Хотя существует несколько кодировок символов, лучше использовать UTF-8.
UTF относится к стандартной кодировке Python, а 8 относится к 8-битным единицам, используемым в кодировке символов. UTF-8 — это стандартная и эффективная кодировка строк Юникода, которая представляет символы в одно-, двух-, трех- или четырехбайтовых блоках. По умолчанию Python использует UTF-8, а это означает, что его не нужно указывать в каждом файле Python.
Чтобы закодировать строку в байты, добавьте метод encode, который будет возвращать двоичное представление строки:
>>> text = 'Hello World'
>>> text.encode('utf-8')
b'Hello Word'
Более сложный вариант:
>>> text = 'parlé'
>>> text.encode('utf-8')
b'parl\xc3\xa9'
>>> text = 'résumé'
>>> text = text.encode('utf-8')
b'r\xc3\xa9sum\xc3\xa9'
Буквы «parl» — это символы ASCII, что позволяет их представлять. Каждый символ в таблице ASCII представляет один байт. Однако сложные символы, такие как é, несовместимы с ASCII в UTF-8 и представлены двумя закодированными байтами: xc3 и xa9, как в первом примере. Во втором примере строки, несовместимые с ASCII, представлены тремя закодированными байтами. UTF-8 может закодировать до четырех байтов. Это означает, что для двоичного представления сложных символов в UTF-8 требуется несколько байтов.
Преобразование байтового объекта в строку называется декодированием. Чтобы декодировать байты в строки, вызовите метод decode() и укажите тип кодировки символов, которую вы хотите использовать:
>>> text = b'parl\xc3\xa9'
>>> text.decode('utf-8')
'parlé'
>>> text = b'r\xc3\xa9sum\xc3\xa9'
>>> text.decode('utf-8)
'résumé'
Когда мы передаем двоичный формат вместе с методом декодирования, на выходе получается исходная строка.
Встроенные функции Python для работы с кодировками
Эти функции Python облегчат работу с кодировками:
- bin() — преобразует целое число в двоичную строку;
- int() — возвращает целое число;
- str() — возвращает строковую версию объекта;
- hex() — преобразует целое число в шестнадцатеричное;
- oct() — возвращает восьмеричное представление целого числа.