Преобразование байтов в строку в 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')
јч
Исходное сообщение было либо, øç
либо јч
, и оба кажутся допустимыми преобразованиями.