Дополнительно. Кодировки и байты
Кодирование символов
Интерпретатор обращается к символу как к некому закодированному значению. Встроенные функции ord()
и chr()
возвращают код символа и символ, обозначающий код, соответственно.
Строку символов можно представить как набор кодов, которые можно получить с помощью цикла и наоборот.
## закодированная строка
for char in 'hello':
print(ord(char))
## строка из списка кодов
out = ''
for code in [104, 101, 108, 108, 111, ]:
out += chr(code)
print(out)
Соответствия кодов и символов были утверждены стандартом ASCII2.
## таблица ASCII2
for code in range(128):
print(code, hex(code), chr(code))
## кириллица в Unicode
for code in range(1000, 1200):
print(code, chr(code))
В интерпретаторе Python все символы хранятся в кодах Unicode. Unicode определяет связь между символом и некоторым числом, но не определяет, как символы будут хранится на жестком диске или передаваться по сети. Поэтому существуют форматы представления текста – как хранить коды unicode. Например, старший байт из трех идет первым или вторым? Наиболее распространенным является представление UTF-8.
Кодирование в UTF-8
Кодирование символа в UTF-8 происходит следующим образом.
- Сначала определяется количество байтов. Номер символа берется из стандарта Unicode.
- Затем устанавливается старший бит, в соответствии с необходимым количеством байт.
- В байте «xхххххx» – это количество значащих бит. Например в первом октете 7 значащих бит – 128 бит.
- Для строк адрес первого байта является адресом строки. Для чисел – знаком.
Шенадцатеричный диапазон номеров | Десятичный диапазон номеров | Требуемое количество октетов (байтов) |
---|---|---|
00000000-0000007F | 0-127 | 1 |
00000080-000007FF | 128-2047 | 2 |
00000800-0000FFFF | 2048-65535 | 3 |
00010000-0010FFFF | 2048-1114111 | 4 |
Количество байтов | Значащий бит | Шаблон |
---|---|---|
1 | 7 | 0xxxxxxx |
2 | 11 | 110xxxxx 10xxxxxx |
3 | 16 | 1110xxxx 10xxxxxx 10xxxxxx |
4 | 21 | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
Байты и свойства
В Python есть тип данных, который позволяет хранить байты — bytes
. Байты содержат коды в шестнадцатеричной системе в зависимость от количества хранимых байт.
Тип данных bytes
имеет те же свойства, что и обычная строка, следовательно можно проводить операции индексации и сложения. bytes
– неизменяемый тип данных.
bb = b'/xd0/xbf/xd1/x80/xd0/xb8/xd0/xb2/xd0/xb5/xd1/x82'
print(
bb[0],
bb.count(0xd0),
b'/xd0/xbf' + b'/xd0/xb8'
)
Задача №6. Байт в символ
Есть символы которые занимают несколько байт в памяти (символы кириллицы занимают по 2 байта). Имеем два байта символа кириллицы в UTF-8. Определить какой символ является полученным байтом?
Решение
Посмотрим представление байтов в двоичном виде с помощью функции bin()
. Получаем значащие биты. Проводим конкатенацию и получаем код символом, который за ним находится.
Выведем на экран каждый байт по отдельности
Значащие биты 10001 и 000100
Формирование байт
При выводе байтов на терминал есть особенность. Латинские символы ASCII при выводе отображаются как символы, а не коды. Выведем на экран код символа «h» в шестнадцатеричной системе. При подстановке полученного значения в байт получим значения символов.
## код символа h в шестнадцатеричной системе
print(hex(ord('h'))) # 0x68
## сформируем строку из байтов
print(b'\x68\x69\x21')
Байтовые строки
Тип данных bytearray
— хранит изменяемую последовательность байтов.
Можно создавать:
- пустые строки,
- пустые массивы байт,
- упорядоченные последовательности,
- строки из списков кодов,
- последовательность байтов в указанной кодировке.
## байтовая строка
ba = bytearray(b'hello')
print(ba)
# пустая байтовая строка
print(bytearray())
# массив байт нулей
print(bytearray(6))
# последовательность байт до 16
print(bytearray(range(16)))
# байтовая строка из списка кодов
print(bytearray([104, 101, 108, 108, 111, ]))
# создание байтовой строки в кодировке utf-8
print(bytearray('привет', encoding='utf-8'))
Кодирование и декодирование
Для преобразования символов Unicode в последовательность байт используется метод строки encode()
.При использования разных кодировок получаются разные символы. Сейчас UTF-8 используется повсеместно, но раньше в разных ОС символы файлов отображались по-разному.
Закодировать строку 'привет'
в байты:
Для декодирования байтовой строки в строку символов — метод строки decode()
.
Python может узнать о кодировке из файле, если указать в первой или второй строках файла следующий комментарий. Если такого комментария нет — то предполагается UTF-8.
Промежуточные итоги
- Python может узнать о кодировке в данном файле, если указать в первой или второй строках файла следующий комментарий.
- Если такого комментария нет – то предполагается UTF-8.
- Каждый символ имеет код в Unicode. Каждый код может быть по-разному представлен в зависимости от кодировки.
- Символы имеют представление в байтах или байтовых строках.
- Файл является объектом в Python и представлен как поток байтов.
- Байты файла можно читать и записывать в другие файлы.