2012-04-04 64 views
9

Tôi biết điều này có vẻ xấu hổ dễ dàng, và tôi đoán vấn đề là tôi chỉ không có một sự hiểu biết rõ ràng về tất cả điều này byte-str-unicode (và giải mã mã hóa, nói thẳng thắn).Giải mã base64 chuỗi trong python 3 (với lxml hay không)

Tôi đã cố gắng lấy mã hoạt động của mình để chạy trên Python 3. Phần tôi đang mắc kẹt là khi tôi phân tích cú pháp XML bằng lxml và giải mã chuỗi base64 trong XML đó.

Mã này hiện đang làm việc trong các cách sau đây:

tôi lấy dữ liệu nhị phân với một truy vấn XPath '.../binary/text()'. Điều này tạo ra một danh sách một phần tử có chứa một đối tượng lxml.etree._ElementUnicodeResult. Sau đó, với python 2, tôi đã có thể làm:

decoded = source.decode('base64') 

và cuối cùng

output = numpy.frombuffer(decoded) 

Tuy nhiên, trên python 3 tôi nhận được một thông báo lỗi nói

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

này không phải là quá đáng ngạc nhiên, bởi vì lxml.etree._ElementUnicodeResult là một phân lớp của str.

Một cách khác là để có được một thực str với cùng một dữ liệu trong nó với

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

Đó sẽ là về cơ bản giống nhau. Vì vậy, tôi phải làm gì để giải mã nó từ base64? Tôi đã xem xét các mô-đun base64, nhưng phải mất một đối tượng bytes làm đối số và tôi không thể nghĩ ra cách để trình bày strbytes, bởi vì nếu tôi cố gắng xây dựng một đối tượng bytes, Python sẽ cố gắng mã hóa chuỗi mà tôi không cần.

Googling hơn nữa, tôi đi qua các mô-đun binascii (được gọi gián tiếp từ base64 dù sao, nếu tôi không nhầm), nhưng gọi binascii.b2a_base64() trên chuỗi của tôi sản xuất

TypeError: 'str' does not support the buffer interface 

T.B. Tôi thậm chí đã tìm thấy một câu hỏi được trả lời trên how to decode a hex string in Python 3, nhưng điều này được thực hiện với một phương pháp chuyên dụng bytes.fromhex() vì vậy tôi không thấy nó sẽ hữu ích như thế nào.

Có thể ai đó vui lòng cho tôi biết tôi đang thiếu gì không? Tôi sợ hầu hết các bài viết là không liên quan và chỉ làm trầm trọng thêm sự xấu hổ của tôi, nhưng ít nhất các bạn biết what I tried.

+4

Ngoài ra, Ned Batchelder có một bản trình bày tuyệt vời về công cụ byte-str-unicode này: [Pragmatic Unicode, hoặc: Làm thế nào để tôi dừng đau?] (Http://nedbatchelder.com/text/unipain.html) – delnan

+0

Cảm ơn @delnan, tôi đang nửa chừng và thực sự đã giúp rất nhiều :) –

Trả lời

2

Tôi chưa cài đặt Python 3, nhưng có vẻ như bạn cần chuyển đổi Unicode trả về từ lxml thành byte, có thể bằng cách gọi .encode ('ascii')?

+0

Gosh ... Tôi biết điều đó thật dễ dàng. Tôi không thể giải quyết vấn đề này trong tâm trí của tôi theo cách của nó. Tôi đã suy nghĩ về chuỗi của mình như là một cái gì đó * mã hóa *, vì vậy nó thực sự đã không xảy ra với tôi rằng tôi cần phải mã hóa nó để có được 'byte'. Cảm ơn. –

+3

Hãy suy nghĩ về Unicode là các chuỗi thuần-vani cần phải được mã hóa khi chúng đến "phần cứng" và được giải mã khi đến từ "phần cứng" :-) – thebjorn

+0

Tôi cảm thấy như một câu hỏi dài cần một câu trả lời dài hơn, nhưng dù sao đi nữa , cảm ơn rất nhiều cho chỉ hướng đúng :) –

6

OK, tôi nghĩ tôi sẽ tóm tắt sự hiểu biết hiện tại của tôi về mọi thứ (cảm thấy tự do để sửa tôi). Hy vọng rằng nó sẽ giúp người khác ra khỏi đó như bối rối như tôi đã từng.

Tín dụng hoàn toàn chuyển sang thebjorndelnan, tất nhiên.

Vì vậy, bắt đầu với những điều phổ biến nhất: có Unicode và đó là tiêu chuẩn toàn cầu gán mã (hoặc điểm mã) cho tất cả các ký tự kỳ lạ bạn có thể tưởng tượng. Những mã này chỉ là số nguyên. Theo Unicode 6.1, có 109.975 ký tự đồ họa, Wikipedia nói.

Sau đó, có mã hóa xác định cách chỉ định các ký tự Unicode với mã byte. Một byte không đủ để chỉ định một char Unicode tùy ý. Mặc dù, nếu bạn chỉ lấy một phần nhỏ của chúng (bảng chữ cái tiếng Anh, chữ số, dấu chấm câu, một số ký tự điều khiển), bạn có thể làm với một byte cho mỗi ký tự (hoặc thậm chí 7 bit; xem ASCII).


Để chuyển chuỗi Unicode ở bất kỳ đâu, bạn cần mã hóa chuỗi theo byte, sau đó mã hóa có thể được giải mã ở đầu bên kia.

Trong Python 2, str thực sự là byte và unicode là Unicode, nhưng Python 2 sẽ mã hóa/giải mã ẩn cho bạn khi cần. Nó sẽ cố gắng sử dụng mã hóa ASCII.

Trong Python 3, str luôn là chuỗi Unicode và bytes là loại dữ liệu mới cho byte thực. Không có chuyển đổi ngầm nào được thực hiện bởi Python 3, bạn luôn cần phải tự mình thực hiện và chỉ định mã hóa. Điều đó có nghĩa là chương trình của bạn sẽ không hoạt động cho đến khi bạn hiểu những gì đang xảy ra, điều đó hoàn toàn xảy ra với tôi.


Hiện tại, ít hoặc rõ ràng, hãy chuyển sang mã hóa base64, đây cũng là một loại mã hóa nhưng có ý nghĩa hơi khác. Giả sử bạn có một số dữ liệu nhị phân (nghĩa là byte) có thể có nghĩa là bất kỳ điều gì (trong trường hợp của tôi là một loạt các float s). Bây giờ bạn muốn biểu diễn mảng nhị phân này bằng một chuỗi. Đó là những gì mã hóa base64 có nghĩa là: bạn có byte của bạn được biểu diễn dưới dạng chuỗi ASCII.

Base64 có nghĩa là 6 bit, vì vậy trong chuỗi được mã hóa base64, một ký tự đơn tượng trưng cho 6 bit dữ liệu của bạn. Đó là lý do tại sao chuỗi được mã hóa base64 cần phải có độ dài là bội số của 4: nếu không số byte được mã hóa sẽ không phải là số nguyên.


Cuối cùng, để giải mã từ base64, bạn cần chuỗi ASCII. Một chuỗi Unicode sẽ không làm, chỉ có thể có các ký tự từ bảng chữ cái base64. Base64 module thực hiện công việc bằng Python. Hàm base64.b64decode() nhận một chuỗi byte làm đối số. Trong Python 2 nó có nghĩa là: str. Trong Python 3 nó có nghĩa là: bytes. Vì vậy, nếu bạn có một str, chẳng hạn như

>>> s = 'U3RhY2sgT3ZlcmZsb3c=' 

Trong Python 2 bạn chỉ có thể làm

>>> s.decode('base64') 

s là đã có trong ASCII. Trong Python 3, bạn cần phải mã hóa nó trong ASCII đầu tiên, vì vậy bạn sẽ phải làm:

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

Và bằng cách này, điều này sẽ trả về một đối tượng bytes, vì vậy nó thực sự tùy thuộc vào bạn như thế nào để xử lý các byte đó.Có lẽ đó là phao của tôi, nhưng có lẽ bạn nên cố gắng giải mã nó như ASCII :) Trong Python 2 tuy nhiên nó sẽ chỉ là một str. Dù sao, hãy xem struct để các công cụ giải nén dữ liệu của bạn khỏi các byte đó.

Vì vậy, nếu bạn cần mã để hoạt động trên cả Python 2 và 3, hãy đi với mã cuối cùng. Để đảm bảo bạn có Unicode cuối cùng (nếu bạn đang giải mã văn bản từ base64), bạn sẽ phải giải mã nó:

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

Mở Python 2, encode('ascii') sẽ không có hiệu quả làm bất cứ điều gì bởi vì nó áp dụng cho str . Vì vậy, nó sẽ thực hiện chuyển đổi ẩn ẩn trước thành Unicode trước và sau đó thực hiện những gì bạn muốn (chuyển đổi nó thành ASCII). decode('ascii') sẽ trả về đối tượng unicode trên Python 2.

+0

Tóm tắt tuyệt vời :-) Nếu bạn đang cố gắng để lưu một danh sách các phao nổi, có lẽ mô-đun dưa sẽ dễ dàng hơn mô-đun struct? Một cái gì đó giống như base64.b64encode (pickle.dumps ([2.718, 3.141])) – thebjorn

+0

@thebjorn Cảm ơn :) Tôi thực sự đang sử dụng 'numpy.frombuffer()', tôi vừa đề cập đến 'struct' để tham khảo, để tính toán cho một tổng quát trường hợp. –

+0

"chương trình của bạn sẽ không hoạt động cho đến khi bạn hiểu những gì đang xảy ra" - đây là một điều tốt, hầu hết thời gian. :) – AKX

Các vấn đề liên quan