Мы переходим к построению клиент-серверного приложения и начнем с самых азов — кодировки в Python
С чего всё начиналось: ASCII
Многие уже знают, что для хранения числовых и текстовых данных в памяти вашего компьютера используются последовательности кодов. Каждая буква записывается как элемент кода в вычислительную память, а при отображении она конвертируется обратно. Очень долгое время, начиная с 60-х годов прошлого века использовался стандарт American Standard Code for Information Interchange или, сокращенно — ASCII. Несмотря на все последующие модификации стандарта, он упёрся в ограничение 256 символов, что, с учетом развития алфавитов многих стран, стало катастрофически мало
ASCII на сегодняшний день используется в крайне редких случаях.
Что такое Unicode?
Unicode — это относительно новый стандарт кодирования, который сейчас повсеместно используется в программировании. Принцип Unicode в диапазоне-последовательности кодовых точек, к которым привязаны определенные символы (буквы, цифры, знаки препинания и т.д.). Кодовое пространство стандарта включает 1 114 112 кодовых точек, находящихся в пределах 0-10FFFF.
Для работы с данными в Unicode принято использовать правило Unicode sandwich — байты из памяти конвертируются в строковый формат (Uncode). Дальше в приложении данные оперируются только в строковом формате. Перед передачей данных мы снова конвертируем строку в байты
Кодировка UTF-8
Чтобы передавать данные по сети нам нужно сконвертировать текст в байты. Для этого и служит одна из версий Unicode — кодировка UTF-8. Она имеет переменную длину кода — это значит, что UTF-8 не использует один байт все время, это от 1 до 4 байтов.
Unicode в Python
Итак, мы определились. Для человека текст — это набор соответствующих символов. Для памяти компьютера — это данные в виде байт. Если это представить через призму языка программирования Python, то мы получим следующее:
- Тип данных str — это текст, он же неизменяемый набор кодов (code points) Unicode;
- Тип данных bytes — это данные (байты), это же неизменяемый набор байтов
Строки
Строка — последовательность кодов Unicode. Её можно представить несколькими способами, в т.ч. с помощью имени символа или особого формата. Для того, чтобы какую-либо строку перевести в unicode-формат, можно воспользоваться онлайн-конвертерами. Можно использовать https://www.branah.com/unicode-converter
[code]
# Создадим переменную с текстом
alcohol = ‘Виски’
print(alcohol)
print(type(alcohol)) # тип — строка
# представление с помощью имени символа
unicode_symbol = ‘\N{LATIN SMALL LETTER C WITH DOT ABOVE}’
print(unicode_symbol)
# представление с помощью особого формата
unicode_symbol2 = ‘\u014C’
print(unicode_symbol2)
# записываем строку, как последовательность юникод-символов
alcohol2 = ‘Хугарден’
alcohol3 = ‘\u0425\u0443\u0433\u0430\u0440\u0434\u0435\u043d’
print(alcohol3)
print(alcohol2 == alcohol3) # здесь у нас будет true, т.к. строки одинаковые
print(len(alcohol3)) #длина строки unicode-типа будет 8 символов, как в слове.
# функция ord получиает числовое значение юникод-символа
print(ord(‘D’))
# функция chr позволяет получить символ по коду
print(chr(220))
[/code]
Байты
Байты в среде разработки Python — это тоже последовательность unicode-символов, но, в отличии от строк, представлены в виде ASCII, а это значит, что при работе с кириллицей будет ошибка. Байтовый тип данных в питоне маркируется английской буквой b
[code]
# Как можно записать строку в байты?
alco1 = b’\u0057\u0068\u0069\u0073\u006b\u0079′
alco2 = b»\u0057\u0068\u0069\u0073\u006b\u0079″
alco3 = b»’\u0057\u0068\u0069\u0073\u006b\u0079»’
print(type(alco1))
print(type(alco2))
print(type(alco3))
print(alco3)
# строка из символов относящихся к ASCII (латиница) и отображается как набор символов
alco4 = b’Whisky’
print(alco4)
# строка из символов не относящихся к ASCII (кириллица)
# при попытке вывода байтового представления будет выведена ошибка
# alco5 = b’Виски’
# print(alco5)
[/code]
Конвертация (decode, encode)
Практически все программы так или иначе работают с сетью или файловой системой, поэтому работа с байтами так или иначе необходима. Чтобы преобразовывать байты в строки (bytes -> str) и наоборот (str -> bytes) используются методы кодирования или декодирования.
[code]
# Из строки в байты (encode)
alco = ‘Виски’
alco_in_bytes = alco.encode(‘utf-8′)
print(alco_in_bytes)
# простое декодирование — decode
alco_bytes = b’\x57\x68\x69\x73\x6b\x79’
alco_in_str = alco_bytes.decode(‘utf-8’)
print(alco_in_str)
# метод encode для класса str (передаем какую строку будем декодировать и указываем кодировку)
alcostr= ‘Виски’
alco_encode = str.encode(alcostr, encoding=’utf-8′)
print(alco_encode)
# метод decode для класса bytes (кодировка указана как ключевой аргумент)
bytesstart = b’\x57\x68\x69\x73\x6b\x79′
bytesend = bytes.decode(bytesstart, encoding=’utf-8′)
print(bytesend)
[/code]
Методы encode и decode можно применять к типам данных str и bytes. В качестве аргумента передается имя переменной и ключ шифрования (кодировка, если по-простому).
Файловая система и кодировка
При работе с операциями над файловой системой необходимо обязательно указывать кодировку, так как в различных ОС — она разная.
[code]
import locale
def_coding = locale.getpreferredencoding()
print(def_coding)
# Создаем файл и записываем в него текст
file= open(‘buhlo.txt’, ‘w’)
file.write(‘party time’)
file.close()
print(type(file))
# явное указание кодировки при работе с файлом
with open(‘buhlo.txt’, encoding=’utf-8′) as file:
for text in file:
print(text, end=»)
[/code]
Обработка ошибок
У методов encode и decode есть режимы обработки ошибок, которые указывают, как реагировать на ошибку преобразования.При использовании метода encode при возникновении ошибок генерируется исключение UnicodeError. У метода decode тоже есть похожий механизм — генерируется исключение UnicodeDecodeError.
[code]
# replace — обработка ошибки кодирования с заменой символа, отсутствующем в указываемой кодировке.
errorword = ‘Partyтайм’
error = errorword.encode(‘ascii’, ‘replace’)
print(error)
# namereplace — обрабатываем ошибку с заменой символа его именем
errorword2 = errorword.encode(‘ascii’, ‘namereplace’)
print(errorword2)
# Игнорирование (ignore) — программа просто пропустит символы, которы
errorword3 = ‘Пати time’
ignore = errorword3.encode(‘ascii’, ‘ignore’)
print(ignore)
# Игнорирование при использовании decode
str = ‘Party тайм’
str_utf8 = str.encode(‘utf-8’)
print(str_utf8)
decoding = str_utf8.decode(‘ascii’, ‘ignore’)
print(decoding)
# replace при использовании decode
str = ‘Party тайм’
str_utf8 = str.encode(‘utf-8’)
print(str_utf8)
decoding = str_utf8.decode(‘ascii’, ‘replace’)
print(decoding)
[/code]
Модуль subprocess
Модуль subprocess отвечает за выполнение следующих действий: порождение новых процессов, соединение c потоками стандартного ввода, стандартного вывода, стандартного вывода сообщений об ошибках и получение кодов возврата от этих процессов. В качестве примера мы используем стандартную команду из cmd — ping.
В этом примере результат работы модуля subprocess — это конвертация каждой из строк в формат кодировки cp866, после чего результат перекодируется в UTF-8. Он представляет собой набор кодов Unicode (байтовый формат). Для дальнейшей работы с результатом как со строкой необходимо преобразовать его в этот тип, то есть выполнить операцию decode.
Вся последовательность действий:
- Байтовый формат cp866 -> строка в формате cp866.
- Строка в формате cp866 -> байтовый формат UTF-8.
- Байтовый формат UTF-8 -> строка в формате UTF-8.
[code]
import subprocess
args = [‘ping’, ‘vk.com’] ping = subprocess.Popen(args, stdout=subprocess.PIPE)
for result in ping.stdout:
result = result.decode(‘cp866’).encode(‘utf-8’)
print(result.decode(‘utf-8’))
[/code]



































































