解码python 3中的base64字符串(带或不带lxml)

Lev*_*sky 10 python base64 lxml python-3.x

我知道这看起来很容易,我想问题是我只是没有清楚地理解所有这些字节-str-unicode(和编码解码,坦率地说)的东西.

我一直在努力让我的工作代码在Python 3上运行.我坚持使用的部分是当我解析XML lxml并解码XML中的base64字符串时.

代码现在以下列方式工作:

我使用XPath查询检索二进制数据'.../binary/text()'.这将生成包含lxml.etree._ElementUnicodeResult对象的单元素列表.然后,使用python 2,我能够做到:

decoded = source.decode('base64')
Run Code Online (Sandbox Code Playgroud)

最后

output = numpy.frombuffer(decoded)
Run Code Online (Sandbox Code Playgroud)

但是,在python 3上,我收到一条错误消息

AttributeError: 'lxml.etree._ElementUnicodeResult' object has no attribute 'decode'
Run Code Online (Sandbox Code Playgroud)

这并不令人惊讶,因为它lxml.etree._ElementUnicodeResult是一个子类str.

另一种方法是str使用相同的数据获得真实

 binary = tree.xpath('//binary')[0]
 binary_string = binary.text
Run Code Online (Sandbox Code Playgroud)

那基本上是一样的.那么我该怎么做才能从base64解码呢?我已经看过了base64模块,但它需要一个bytes对象作为参数,我不能想到的呈现方式strbytes,因为如果我试图建立一个bytes对象,Python会编码字符串,这我不不需要.

谷歌搜索进一步,我遇到了binascii模块(base64无论如何我都是间接调用的,如果我没有弄错的话),但是调用binascii.b2a_base64()我的字符串会产生

TypeError: 'str' does not support the buffer interface
Run Code Online (Sandbox Code Playgroud)

PS我甚至找到了一个关于如何在Python 3中解码十六进制字符串的问题,但这是通过专用方法完成的,bytes.fromhex()所以我看不出它会有什么帮助.

有人可以告诉我我错过了什么吗?我担心大部分帖子都无关紧要,只会加重我的耻辱,但至少你们知道我尝试了什么.

Lev*_*sky 8

好吧,我想我将总结一下我目前对事物的理解(随意纠正我).希望它会像我一样困扰那里的其他人.

当然,信用完全归功于比约恩德尔南.

因此,从最常见的事情开始:有Unicode,它是一个全局标准,可以为您可以想象的所有奇异角色分配代码(或代码点).这些代码只是整数.维基百科说,从Unicode 6.1开始,有109,975个图形字符.

然后有编码定义如何使用字节代码指定Unicode字符.一个字节不足以指定任意Unicode字符.虽然,如果你只取一小部分(英文字母,数字,标点符号,一些控制字符),你可以使用每个字符一个字节(甚至7位;参见ASCII).


要在任何地方传递Unicode字符串,需要以字节为单位对其进行编码,然后在另一端对其进行解码.

在Python 2中,str实际上是字节,并且unicode是Unicode,但Python 2将在需要时为您执行隐式编码/解码.它会尝试使用ASCII编码.

在Python 3中,str始终是Unicode字符串,并且bytes是实际字节的新数据类型.Python 3没有进行任何隐式转换,您总是需要自己完成并指定编码.这意味着你的程序将无法运行,直到你理解发生了什么,这完全发生在我身上.


现在,或多或少,我们继续使用base64编码,这也是一种编码,但含义略有不同.假设你有一些二进制数据(即字节)可能意味着什么(在我的情况下,它是一堆floats).现在,您想用字符串表示此二进制数组.这就是base64编码的含义:您将字节表示为ASCII字符串.

Base64表示6位,因此在base64编码的字符串中,单个字符代表6位数据.这就是为什么base64编码的字符串需要的长度是4的倍数:否则编码的字节数将不是整数.


最后,要从base64解码,您需要一个ASCII字符串.Unicode字符串不起作用,只能有base64字母表中的字符.Base64模块在Python中完成工作.该base64.b64decode()函数采用字节字符串作为参数.在Python 2中它意味着:str.在Python 3中,它意味着:bytes.所以如果你有str,比如

>>> s = 'U3RhY2sgT3ZlcmZsb3c='
Run Code Online (Sandbox Code Playgroud)

在Python 2中你可以做到

>>> s.decode('base64')
Run Code Online (Sandbox Code Playgroud)

因为s已经是ASCII.在Python 3中,您需要首先使用ASCII编码,因此您必须执行以下操作:

>>> base64.b64decode(s.encode('ascii'))
Run Code Online (Sandbox Code Playgroud)

顺便说一句,这将返回一个bytes对象,所以你应该如何处理这些字节.也许这是我的花车,但也许你应该尝试将它解码为ASCII :)但是在Python 2中它只是一个str.无论如何,请查看struct从这些字节解压缩数据的工具.

因此,如果您需要在Python 2和3上运行代码,请使用最后一个代码.为了确保你最终有Unicode(如果你正在解码base64中的文本),你将不得不解码它:

>>> base64.b64decode(s.encode('ascii')).decode('ascii')
Run Code Online (Sandbox Code Playgroud)

在Python 2上,encode('ascii')因为它被应用于,所以不会有效地做任何事情str.因此,它将首先隐式转换为Unicode,然后执行您想要的操作(将其转换回ASCII).decode('ascii')unicode在Python 2上返回一个对象.


the*_*orn 2

我没有安装 Python 3,但听起来您需要将从 lxml 返回的 Unicode 转换为字节,也许通过调用 .encode('ascii') ?

  • 将 Unicode 视为普通字符串,当它们进入“硬件”时需要进行编码,而来自“硬件”时需要进行解码:-) (4认同)