2012-04-04 74 views
9

我知道这看起来令人尴尬的容易,我想这个问题是我根本没有这一切字节-STR-unicode的清醒的认识(和编码解码,坦率地说)的东西呢。解码的base64字符串在Python 3(与LXML与否)

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

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

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

decoded = source.decode('base64') 

最后

output = numpy.frombuffer(decoded) 

然而,在Python 3中,我得到一个错误信息说

AttributeError: 'lxml.etree._ElementUnicodeResult' object has no attribute 'decode' 

事实并非如此令人惊讶,因为lxml.etree._ElementUnicodeResultstr的子类。

另一种方法是,以获得真正的str与它相同的数据与

binary = tree.xpath('//binary')[0] 
binary_string = binary.text 

这将是基本相同的。那么我该怎么做从base64解码它呢?我已经看了base64模块,但它需要一个bytes对象作为参数,我想不出将str作为bytes的方式,因为如果我尝试构造一个bytes对象,Python将尝试编码字符串,我不需要。

进一步谷歌搜索,我整个binascii模块来(这是从base64间接调用,无论如何,如果我没有记错的话),但我的字符串调用binascii.b2a_base64()产生

TypeError: 'str' does not support the buffer interface 

附:我甚至在how to decode a hex string in Python 3上找到了一个回答问题,但是这是通过专门的方法bytes.fromhex()完成的,所以我不认为它会有帮助。

可能有人请告诉我,我缺少的是什么?恐怕大部分帖子都是无关紧要的,只会加重我的耻辱,但至少你们知道what I tried

+4

顺便说一句,Ned Batchelder在这个bytes-str-unicode的东西上有一个很棒的介绍:[Pragmatic Unicode,或者:如何阻止疼痛?](http:/ /nedbatchelder.com/text/unipain.html) – delnan 2012-04-04 21:11:08

+0

谢谢@delnan,我到一半,真正帮助了很多已经:) – 2012-04-04 21:51:10

回答

2

我没有Python 3的安装,但它听起来像你需要转换Unicode的从LXML返回字节,也许是通过调用.encode(“ASCII”)?

+0

天哪......我知道这是很容易。我无法按照应有的方式来解决这个问题。我一直在想我的字符串是* *编码的*,所以我不会想到我需要对它进行编码以获得'字节'。谢谢。 – 2012-04-04 21:24:25

+3

思考的Unicode为需要进行编码时,他们将“硬件”和解码从:-) – thebjorn 2012-04-04 21:28:19

+0

我觉得像这么长的问题,需要一个较长的答案“硬件”何时到来纯香草字符串,但不管怎么说,非常感谢您指出正确的方向:) – 2012-04-05 12:09:09

6

OK,我想我会总结我目前的东西(随时纠正我)认识。希望它能帮助那些像我一样困惑的人。

信用完全去thebjorndelnan,当然。

因此,从最常见的东西开始: 有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编码,这也是各种各样的编码,但有一个稍微不同的含义。 假设你有一些二进制数据(即字节),这可能意味着什么(在我的情况下,它是一堆float s)。现在你想用一个字符串表示这个二进制数组。这就是base64编码的含义:您将您的字节表示为ASCII字符串。

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


最后,要从base64解码,您需要一个ASCII字符串。一个Unicode字符串不行,只能有base64字母表中的字符。 Base64 module在Python中完成这项工作。 base64.b64decode()函数采用字节字符串作为参数。在Python 2中,它表示:str。在Python 3中,它表示:bytes。所以,如果你有一个str,如

>>> s = 'U3RhY2sgT3ZlcmZsb3c=' 

在Python 2,你可以只是做

>>> s.decode('base64') 

因为s已经在ASCII。 在Python 3,您需要编码它在ASCII第一,所以你要做的:

>>> base64.b64decode(s.encode('ascii')) 

顺便说一下,这将返回一个bytes对象,所以这真的取决于你如何然后处理那些字节。也许这是我的花车,但也许你应该尝试把它当作ASCII解码:) 在Python 2但它只是一个str。无论如何,看看struct的工具来解压你的数据从这些字节。

所以,如果你需要的代码到两个Python 2和3的工作,去的最后一个。为了确保您使用Unicode到底(如果你是从解码的base64文本),你必须对它进行解码:

>>> base64.b64decode(s.encode('ascii')).decode('ascii') 

在Python 2中,因为它适用于strencode('ascii')将不能有效地做任何事。所以它会先执行一个隐式转换到Unicode,然后做你想做的事(把它转换回ASCII)。 decode('ascii')将在Python 2上返回一个unicode对象。

+0

优秀的总结:-)如果你想保存一个浮点列表,也许pickle模块比结构模块更容易?喜欢的东西base64.b64encode(pickle.dumps([2.718,3.141])) – thebjorn 2012-04-05 18:07:56

+0

@thebjorn谢谢:)我实际使用'numpy.frombuffer()',我刚才提到的'参考struct',占一般案件。 – 2012-04-05 18:24:36

+0

“只有在你明白发生了什么之后,你的程序才会起作用” - 大多数情况下,这是一件好事。 :) – AKX 2012-04-06 23:01:04