wake-up-neo.com

Warum brauche ich 'b', um eine Python-Zeichenfolge mit Base64 zu kodieren?

Nach diesem Python-Beispiel kodiere ich einen String als Base64 mit:

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

Wenn ich jedoch den führenden b weglasse:

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

Ich erhalte folgende Fehlermeldung:

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

Warum ist das?

176
dublintech

für die base64-Codierung werden 8-Bit-Binärbyte-Daten verwendet, und für die Codierung werden nur die Zeichen A-Z, a-z, 0-9, +, / * verwendet, damit sie über Kanäle übertragen werden können, die nicht alle 8-Bit-Daten wie E-Mail enthalten.

Daher will es eine Zeichenfolge von 8-Bit-Bytes. Sie erstellen diese in Python 3 mit der b''-Syntax.

Wenn Sie die Variable b entfernen, wird daraus eine Zeichenfolge. Eine Zeichenfolge ist eine Folge von Unicode-Zeichen. base64 hat keine Ahnung, was mit Unicode-Daten zu tun ist, es ist nicht 8-Bit. Es sind eigentlich keine Bits. :-)

In Ihrem zweiten Beispiel:

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

Alle Zeichen passen gut in den ASCII - Zeichensatz, und die Base64-Kodierung ist daher eigentlich etwas sinnlos. Sie können es stattdessen mit in ASCII konvertieren

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

Oder einfacher:

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

Was wäre in diesem Fall dasselbe.


* Die meisten base64-Geschmacksrichtungen können am Ende einen = als Auffüllung enthalten. Außerdem können einige base64-Varianten andere Zeichen als + und / verwenden. Eine Übersicht finden Sie in der Varianten-Übersichtstabelle bei Wikipedia.

193
Lennart Regebro

Kurze Antwort

Sie müssen ein bytes-like-Objekt (bytes, bytearray usw.) an die base64.b64encode()-Methode senden. Hier gibt es zwei Möglichkeiten:

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

Oder mit einer Variable:

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

Warum?

In Python 3 sind str-Objekte keine Zeichen-Arrays im C-Stil (also nicht - Byte-Arrays), sondern Datenstrukturen, die keine inhärente Kodierung aufweisen. Sie können diese Zeichenfolge auf verschiedene Arten kodieren (oder interpretieren). Die häufigste (und in Python 3 Standard) ist utf-8, zumal es mit ASCII abwärtskompatibel ist (obwohl, wie bei den am häufigsten verwendeten Kodierungen). Das passiert, wenn Sie eine string nehmen und die .encode()-Methode aufrufen: Python interpretiert die Zeichenfolge in utf-8 (die Standardcodierung) und stellt Ihnen das entsprechende Byte-Array zur Verfügung.

Base-64-Kodierung in Python 3

Ursprünglich wurde im Fragetitel nach der Base-64-Kodierung gefragt. Lesen Sie weiter für Base-64.

base64-Codierung verwendet 6-Bit-Binärblöcke und codiert sie mit den Zeichen AZ, az, 0-9, '+', '/' und '=' (bei einigen Codierungen werden anstelle von '+' und '/' unterschiedliche Zeichen verwendet. ). Dies ist eine Zeichencodierung, die auf dem mathematischen Konstrukt des Radix-64- oder Basis-64-Zahlensystems basiert, aber sie sind sehr unterschiedlich. Base-64 ist in Mathematik ein Zahlensystem wie Binär- oder Dezimalzahl, und Sie ändern diese Basis für die gesamte Zahl oder (wenn die Basis, aus der Sie konvertieren, eine Potenz von 2 oder weniger als 64 ist) in Abschnitten von rechts nach rechts links.

Bei der Codierung base64 erfolgt die Übersetzung von links nach rechts. Diese ersten 64 Zeichen heißen base64coding. Das 65. "=" - Symbol wird zum Auffüllen verwendet, da die Codierung 6-Bit-Chunks zieht, die Daten, die normalerweise codiert werden sollen, jedoch aus 8-Bit-Bytes bestehen, sodass im letzten Chunk manchmal nur zwei oder vier Bits vorhanden sind.

Beispiel:

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

Wenn Sie diese binären Daten als eine einzelne Ganzzahl interpretieren, konvertieren Sie sie in Basis-10 und Basis-64 ( Tabelle für Basis-64 ):

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

base64coding gruppiert diese Daten jedoch auf diese Weise neu:

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' ist also die Basis-64-Version unserer Binärdatei, mathematisch gesehen. Allerdings muss base64coding die Kodierung in die entgegengesetzte Richtung durchführen (die Rohdaten werden also in 'dGVzdA' konvertiert). Außerdem hat sie eine Regel, die anderen Anwendungen mitteilt, wie viel Platz am Ende übrig bleibt. Dies geschieht durch Auffüllen des Endes mit '='. Die base64-Kodierung dieser Daten ist also 'dGVzdA ==', wobei zwei '=' - Symbole zur Kennzeichnung von zwei Bitpaaren vom Ende entfernt werden müssen, wenn diese Daten decodiert werden, damit sie mit den ursprünglichen Daten übereinstimmen.

Lassen Sie uns dies testen, um zu sehen, ob ich unehrlich bin:

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

Warum base64-Codierung verwenden?

Angenommen, ich muss einige Daten per E-Mail an jemanden senden, z. B. diese Daten:

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

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

Ich habe zwei Probleme angelegt:

  1. Wenn ich versuchte, diese E-Mail in Unix zu senden, würde die E-Mail gesendet, sobald das Zeichen \x04 gelesen wurde, da dies ASCII für END-OF-TRANSMISSION (Ctrl-D) ist, sodass die restlichen Daten nicht berücksichtigt werden die Übertragung.
  2. Auch wenn Python intelligent genug ist, um alle meine bösen Steuerzeichen zu schützen, wenn ich die Daten direkt drucke. Wenn diese Zeichenfolge als ASCII-Zeichen dekodiert wird, können Sie sehen, dass die 'msg' nicht vorhanden ist. Das ist, weil ich drei BACKSPACE-Zeichen und drei SPACE-Zeichen verwendet habe, um die 'msg' zu löschen. Selbst wenn ich dort nicht das Zeichen EOF hätte, könnte der Endbenutzer den Text auf dem Bildschirm nicht in die realen Rohdaten übersetzen.

Dies ist nur eine Demo, die Ihnen zeigt, wie schwierig es sein kann, Rohdaten einfach zu senden. Durch die Kodierung der Daten im base64-Format erhalten Sie exakt dieselben Daten, jedoch in einem Format, das sicher für das Senden über elektronische Medien wie E-Mail ist.

110
Greg Schmit

Wenn die zu codierenden Daten "exotische" Zeichen enthalten, denke ich, dass Sie in "UTF-8" codieren müssen.

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

Wenn der String Unicode ist, ist der einfachste Weg:

import base64                                                        

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

print(b)    
11
alfredocambera

Es gibt alles was Sie brauchen:

expected bytes, not str

Die führende Variable b macht Ihre Zeichenfolge binär.

Welche Python-Version verwenden Sie? 2.x oder 3.x?

Edit: Siehe http://docs.python.org/release/3.0.1/whatsnew/3.0.html#text-vs-data-instead-of-unicode-vs-8-bit für die blutigen Details von Strings in Python 3.x

10
user647772

Dies bedeutet einfach, dass Sie die Eingabe als Byte- oder Byte-Array und nicht als Zeichenfolge verwenden.

0
Atul6.Singh