12

これは恥ずかしいほど簡単に見えますが、問題は、このbytes-str-unicode (およびencoding-decoding、率直に言って)のすべてをまだ明確に理解していないことだと思います。

私は自分の作業コードを Python 3 で実行しようとしています。私が立ち往生しているのは、XML を解析し、lxmlその XML にある base64 文字列をデコードするときです。

コードは次のように動作するようになりました。

XPath クエリを使用してバイナリ データを取得します'.../binary/text()'lxml.etree._ElementUnicodeResultこれにより、オブジェクトを含む 1 要素のリストが生成されます。次に、python 2で、次のことができました:

decoded = source.decode('base64')

そして最後に

output = numpy.frombuffer(decoded)

ただし、python 3では、次のエラーメッセージが表示されます

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

lxml.etree._ElementUnicodeResultは のサブクラスであるため、これはそれほど驚くべきことではありませんstr

str別の方法は、同じデータを含む実数を取得することです

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

それは本質的に同じでしょう。では、base64 からデコードするにはどうすればよいでしょうか。私はbase64モジュールを見てきましたが、それはbytes引数としてオブジェクトを取り、オブジェクトを構築しようとすると、Python は文字列をエンコードstrしようとするため、として表示する方法を考えることができません。いらない。bytesbytes

binasciiさらにグーグルで調べたところ、モジュールに出くわしました(base64間違っていなければ、とにかく間接的に呼び出されます)がbinascii.b2a_base64()、文字列を呼び出すと生成されます

TypeError: 'str' does not support the buffer interface

PS Python 3 で 16 進文字列をデコードする方法に関する回答済みの質問も見つけましたが、これは専用の方法で行われるbytes.fromhex()ため、どのように役立つかわかりません。

誰かが私に欠けているものを教えてもらえますか? 残念ながら、投稿のほとんどは無関係であり、私の恥を悪化させるだけですが、少なくとも皆さんは私が試したことを知っています.

4

2 に答える 2

11

わかりました、私は物事についての私の現在の理解を要約しようと思います (遠慮なく私を訂正してください)。うまくいけば、私と同じように混乱している他の誰かを助けることができます.

もちろん、クレジットは完全にthebjorndelnanにあります。

それでは、最も一般的なものから始めましょう。Unicodeがあります。これは、想像できるすべてのエキゾチックな文字にコード (またはコード ポイント) を割り当てるグローバル標準です。これらのコードは単なる整数です。ウィキペディアによると、Unicode 6.1 の時点で、109,975 のグラフィック文字があります。

次に、Unicode 文字をバイトコードで指定する方法を定義するエンコーディングがあります。任意の Unicode 文字を指定するには、1 バイトでは不十分です。ただし、それらの小さなサブセット (英語のアルファベット、数字、句読点、いくつかの制御文字) のみを使用する場合は、1 文字あたり 1 バイト (または 7 ビット。ASCIIを参照) で行うことができます。


Unicode 文字列をどこにでも渡すには、それをバイト単位でエンコードする必要があり、それから相手側でデコードできます。

Python 2 では、strは実際にはバイトであり、unicodeUnicode ですが、Python 2 は必要に応じて暗黙的なエンコード/デコードを行います。ASCII エンコーディングを使用しようとします。

Python 3 では、strは常に Unicode 文字列であり、bytes実際のバイトの新しいデータ型です。Python 3 によって暗黙的な変換が行われることはありません。常に自分で行い、エンコーディングを指定する必要があります。つまり、何が起こっているのかを理解するまで、プログラムは機能しません。これは完全に私に起こりました。


さて、多かれ少なかれ明確になったので、base64エンコーディングに移りましょう。これも一種のエンコーディングですが、意味が少し異なります。何かを意味する可能性のあるバイナリデータ(つまり、 bytes)があるとします(私の場合、それはfloats の束です)。次に、このバイナリ配列を文字列で表現します。これが base64 エンコーディングの意味です。バイトを ASCII 文字列として表します。

Base64 は 6 ビットを意味するため、base64 でエンコードされた文字列では、1 文字が 6 ビットのデータを表します。これが、base64 でエンコードされた文字列の長さが 4 の倍数である必要がある理由です。そうしないと、エンコードされたバイト数が整数になりません。


最後に、base64 からデコードするには、ASCII 文字列が必要です。Unicode 文字列は使用できません。base64 アルファベットの文字のみを使用できます。Base64 モジュールは 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 では、encode('ascii')に適用されるため、実質的に何もしませんstr。したがって、最初に Unicode への暗黙的な変換を行い、次に必要なことを行います (ASCII に変換します)。Python 2 ではオブジェクトdecode('ascii')を返します。unicode

于 2012-04-05T12:07:57.060 に答える
2

Python 3 をインストールしていませんが、おそらく .encode('ascii') を呼び出して、lxml から返された Unicode をバイトに変換する必要があるようです。

于 2012-04-04T21:16:53.460 に答える