Зачем мне нужно 'b' для кодирования строки с Base64?

После этого пример python, я кодирую строку как Base64 с помощью

>>> import base64
>>> encoded = base64.b64encode(b'data to be encoded')
>>> encoded
b'ZGF0YSB0byBiZSBlbmNvZGVk'

Но, если я не буду лидировать b:

>>> encoded = base64.b64encode('data to be encoded')

Я получаю следующую ошибку:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python32\lib\base64.py", line 56, in b64encode
   raise TypeError("expected bytes, not %s" % s.__class__.__name__)
   TypeError: expected bytes, not str

Почему это?

Ответ 1

base64-кодирование принимает 8-битные двоичные байтовые данные и кодирует его, используя только символы A-Z, A-Z, 0-9, +, / *, поэтому он может передаваться по каналам, которые не сохраняются все 8-битные данные, такие как электронная почта.

Следовательно, он хочет строку из 8-битных байтов. Вы создаете их в Python 3 с синтаксисом b''.

Если вы удалите b, он станет строкой. Строка представляет собой последовательность символов Юникода. base64 не имеет понятия, что делать с данными Unicode, это не 8-бит. На самом деле это не бит.: -)

В вашем втором примере:

>>> encoded = base64.b64encode('data to be encoded')

Все символы аккуратно вписываются в набор символов ASCII, поэтому кодирование base64 на самом деле немного бессмысленно. Вы можете преобразовать его в ascii вместо

>>> encoded = 'data to be encoded'.encode('ascii')

Или проще:

>>> encoded = b'data to be encoded'

В этом случае это будет одно и то же.


* В большинстве дополнений base64 также может быть = в конце в качестве дополнения. Кроме того, некоторые варианты base64 могут использовать символы, отличные от + и /. Подробнее см. В сводной таблице вариантов в Википедии.

Ответ 2

Короткий ответ

Вам нужно нажать bytes-like объекта (bytes, bytearray и т.д.) к base64.b64encode() метод. Вот два способа:

>>> data = base64.b64encode(b'data to be encoded')
>>> print(data)
b'ZGF0YSB0byBiZSBlbmNvZGVk'

Или с переменной:

>>> string = 'data to be encoded'
>>> data = base64.b64encode(string.encode())
>>> print(data)
b'ZGF0YSB0byBiZSBlbmNvZGVk'

Зачем?

В Python 3 объекты str не являются массивами символов C-стиля (поэтому они не являются массивами байтов), а скорее являются структурами данных, которые не имеют встроенной кодировки. Вы можете кодировать эту строку (или интерпретировать ее) различными способами. Наиболее распространенным (и по умолчанию в Python 3) является utf-8, тем более что он обратно совместим с ASCII (хотя, как и наиболее широко используемые кодировки). Это то, что происходит, когда вы берете string и вызываете метод .encode(): Python интерпретирует строку в utf-8 (кодировка по умолчанию) и предоставляет вам массив байтов, которому он соответствует.

Кодировка Base-64 в Python 3

Первоначально заголовок вопроса спрашивал о кодировке Base-64. Читайте дальше для материала Base-64.

base64 кодирование принимает 6-битные двоичные фрагменты и кодирует их с использованием символов AZ, az, 0-9, '+', '/' и '=' (некоторые кодировки используют вместо символов "+" и "/" разные символы,). Это кодировка символов, основанная на математической конструкции системы чисел radix-64 или base-64, но они очень разные. Base-64 в математике - это система чисел, такая как двоичная или десятичная, и вы делаете это изменение радиуса на весь номер, или (если радиус, из которого вы конвертируете, имеет мощность 2 меньше 64) в кусках справа оставил.

В кодировке base64 перевод выполняется слева направо; эти первые 64 символа являются причиной того, что он называется кодировкой base64. Символ 65-го '=' используется для заполнения, поскольку кодирование вытягивает 6-битные куски, но данные, которые обычно предназначены для кодирования, являются 8-битными байтами, поэтому иногда в последнем фрагменте всего два или четыре бита.

Пример:

>>> data = b'test'
>>> for byte in data:
...     print(format(byte, '08b'), end=" ")
...
01110100 01100101 01110011 01110100
>>>

Если вы интерпретируете эти двоичные данные как одно целое число, тогда вы можете преобразовать его в base-10 и base-64 (таблица для base-64):

base-2:  01 110100 011001 010111 001101 110100 (base-64 grouping shown)
base-10:                            1952805748
base-64:  B      0      Z      X      N      0

base64 кодирование, однако, будет повторно группа этих данных таким образом:

base-2:  011101  000110  010101 110011 011101 00(0000) <- pad w/zeros to make a clean 6-bit chunk
base-10:     29       6      21     51     29      0
base-64:      d       G       V      z      d      A

Итак, "B0ZXN0" - это математическая версия нашей бинарной версии base-64. Однако кодировка base64 должна выполнять кодировку в противоположном направлении (поэтому исходные данные преобразуются в "dGVzdA"), а также имеет правило сообщать другим приложениям, сколько места осталось в конце. Это делается путем заполнения конца символами '='. Таким образом, кодировка base64 этих данных - "dGVzdA ==", при этом два символа "=" для обозначения двух пар бит должны быть удалены с конца, когда эти данные будут декодированы, чтобы они соответствовали исходным данным.

Позвольте проверить это, чтобы увидеть, не ли я нечестно:

>>> encoded = base64.b64encode(data)
>>> print(encoded)
b'dGVzdA=='

Зачем использовать кодировку base64?

Скажем, я должен отправить некоторые данные кому-то по электронной почте, как эти данные:

>>> data = b'\x04\x6d\x73\x67\x08\x08\x08\x20\x20\x20'
>>> print(data.decode())

>>> print(data)
b'\x04msg\x08\x08\x08   '
>>>

Есть две проблемы, которые я поставил:

  1. Если бы я попытался отправить это письмо в Unix, письмо отправит, как только будет \x04 символ \x04, потому что это ASCII для END-OF-TRANSMISSION (Ctrl-D), так что оставшиеся данные будут исключены из коробка передач.
  2. Кроме того, хотя Python достаточно умен, чтобы избежать всех моих злых контрольных символов, когда я печатаю данные напрямую, когда эта строка декодируется как ASCII, вы можете видеть, что "msg" не существует. Это потому, что я использовал три символа BACKSPACE и три SPACE чтобы стереть "msg". Таким образом, даже если бы у меня не было символа EOF конечный пользователь не смог бы перевести текст с экрана на реальные необработанные данные.

Это просто демоверсия, чтобы показать вам, как сложно просто отправить необработанные данные. Кодирование данных в формат base64 дает вам точные данные, но в формате, который гарантирует, что он безопасен для отправки через электронные носители, такие как электронная почта.

Ответ 3

Если кодируемые данные содержат "экзотические" символы, я думаю, вам нужно кодировать в "UTF-8"

encoded = base64.b64encode (bytes('data to be encoded', "utf-8"))

Ответ 5

Если строка является Unicode, самый простой способ:

import base64                                                        

a = base64.b64encode(bytes(u'complex string: ñáéíóúÑ', "utf-8"))

# a: b'Y29tcGxleCBzdHJpbmc6IMOxw6HDqcOtw7PDusOR'

b = base64.b64decode(a).decode("utf-8", "ignore")                    

print(b)
# b :complex string: ñáéíóúÑ

Ответ 6

Это просто означает, что вы воспринимаете ввод как байты или байты, а не как строки.