Преобразование байтов в строку в Python
В этой статье мы рассмотрим, как преобразовать байты в строку в Python. К концу этой статьи у вас будет четкое представление о том, что это за типы и как эффективно обрабатывать данные с их помощью.
В зависимости от версии Python, которую вы используете, эта задача будет отличаться. Хотя Python 2 подошел к концу, многие проекты все еще используют его, поэтому мы включим оба подхода - Python 2 и Python 3.
Преобразование байтов в строку в Python 3
Начиная с Python 3, пришлось отказаться от старого способа работы с ASCII, и Python стал полностью Unicode.
Это означает, что мы потеряли явный тип Unicode: u"string" - каждая строка - это u"string"!
Чтобы отличить эти строки от старых добрых строк байтов, мы познакомились с новым спецификатором для них - b"string".
Это было добавлено в Python 2.6, но не служило реальной цели, кроме подготовки к Python 3, поскольку все строки были байтовыми строками в 2.6.
Строки байтов в Python 3 официально называются bytes, неизменной последовательностью целых чисел в диапазоне 0 <= x <256. Другой bytes - подобный объект, добавленный в 2.6, bytearray - похож на bytes, но изменяемый.
Преобразование байтов в строку с помощью decode()
Давайте посмотрим, как мы можем преобразовать байты в String, используя встроенный метод decode() для класса bytes:
b = b"Lets grab a \xf0\x9f\x8d\x95!"
# Let's check the type
print(type(b))
# <class 'bytes'>
# Now, let's decode/convert them into a string
s = b.decode('UTF-8')
print(s)
# "Let's grab a 🍕!"
Передав формат кодирования, мы преобразовали объект bytes в строку и распечатали ее.
Преобразование байтов в строку с кодеками
Как вариант, для этой цели мы можем использовать встроенный модуль codecs:
import codecs
b = b'Lets grab a \xf0\x9f\x8d\x95!'
print(codecs.decode(b, 'UTF-8'))
# "Let's grab a 🍕!"
Вам действительно не нужно передавать параметр кодировки, однако рекомендуется передавать его:
print(codecs.decode(b))
# "Let's grab a 🍕!"
Преобразование байтов в строку с помощью str()
Наконец, вы можете использовать str()функцию, которая принимает различные значения и преобразует их в строки:
b = b'Lets grab a \xf0\x9f\x8d\x95!'
print(str(b, 'UTF-8'))
# "Let's grab a 🍕!"
Не забудьте указать аргумент кодировки str(), иначе вы можете получить неожиданные результаты:
print(str(b))
# b'Lets grab a \xf0\x9f\x8d\x95!'
Это снова подводит нас к кодировкам. Если вы укажете неправильную кодировку, в лучшем случае произойдет сбой вашей программы, потому что она не может декодировать данные. Например, если бы мы попытались использовать функцию str() с UTF-16, нас бы встретили:
print(str(b, 'UTF-16'))
# '敌❴\u2073牧扡愠\uf020趟↕'
Это даже более важно, учитывая, что Python 3 любит использовать Unicode, поэтому, если вы работаете с файлами или источниками данных, которые используют непонятную кодировку, обязательно обратите на это особое внимание.
Преобразование байтов в строку в Python 2
В Python 2 набор байтов и строка - это практически одно и то же: строки - это объекты, состоящие из однобайтовых символов, что означает, что каждый символ может хранить 256 значений. Вот почему их иногда называют строками байтов.
Это замечательно при работе с байтовыми данными - мы просто загружаем их в переменную и готовы к печати:
s = "Hello world!"
print(s)
# 'Hello world!'
print(len(s))
# 12
Однако использование символов Unicode в строках байтов немного меняет это поведение:
s = "Let's grab a 🍕!"
print(s)
# 'Lets grab a \xf0\x9f\x8d\x95!'
# Where has the pizza gone to?
print(len(s))
# 17
# Shouldn't that be 15?
Преобразование байтов в Unicode (Python 2)
Здесь нам придется использовать тип Python 2 Unicode, который предполагается и автоматически используется в Python 3. В нем строки хранятся как последовательность кодовых точек, а не байтов.
Представляет собой байты \xf0\x9f\x8d\x95, последовательность шестнадцатеричных чисел и Python не знает, как представить их в виде ASCII:
>>> u = u"Let's grab a 🍕!"
u"Let's grab a \U0001f355!""
>>> u
"Let's grab a 🍕!"
# Yum.
>>> len(u)
15
Как вы можете видеть выше, строка Unicode содержит \U0001f355 - экранированный символ Unicode, который наш терминал распечатывает как кусок пиццы! Установить это было так же просто, как использовать спецификатор u перед значением байтовой строки.
Итак, как мне переключаться между ними?
Вы можете получить строку Unicode, расшифровав свою байтовую строку. Это можно сделать, создав объект Unicode, предоставив байтовую строку и строку, содержащую имя кодировки в качестве аргументов, или вызвав .decode(encoding) у байтовой строки.
Преобразование байтов в строку с помощью decode() (Python 2)
Вы также можете использовать codecs.encode(s, encoding) из модуля codecs.
>>> s = "Let's grab a \xf0\x9f\x8d\x95!"
>>> u = unicode(s, 'UTF-8')
>>> u
"Let's grab a 🍕!"
>>> s.decode('UTF-8')
"Let's grab a 🍕!"
Преобразование байтов в строку с помощью кодеков (Python 2)
Или, используя модуль codecs:
import codecs
>>> codecs.decode(s, 'UTF-8')
"Let's grab a 🍕!"
Помните о своей кодировке
Здесь следует предостеречь - байты могут по-разному интерпретироваться в разных кодировках. Из- за того, что из коробки доступно около 80 различных кодировок, может быть нелегко узнать, есть ли у вас правильная!
s = '\xf8\xe7'
# This one will let us know we used the wrong encoding
>>> s.decode('UTF-8')
UnicodeDecodeError: 'utf8' codec can't decode byte 0xf8 in position 0:
invalid start byte
# These two overlaps and this is a valid string in both
>>> s.decode('latin1')
øç
s.decode('iso8859_5')
јч
Исходное сообщение было либо, øç либо јч, и оба кажутся допустимыми преобразованиями.