8

requests moduleを使用してWebサービスから取得したユニコード文字列には、バイナリ文書(PCL)が含まれています。これらのバイトの一つは、値248を持ち、base64でエンコードしようと、それは次のようなエラーにつながる:PythonのUnicode文字列をBase64でエンコードするbase64 2.7

In [68]: base64.b64encode(response_dict['content']+'\n') 
--------------------------------------------------------------------------- 
UnicodeEncodeError      Traceback (most recent call last) 
C:\...\<ipython-input-68-8c1f1913eb52> in <module>() 
----> 1 base64.b64encode(response_dict['content']+'\n') 

C:\Python27\Lib\base64.pyc in b64encode(s, altchars) 
    51  """ 
    52  # Strip off the trailing newline 
---> 53  encoded = binascii.b2a_base64(s)[:-1] 
    54  if altchars is not None: 
    55   return _translate(encoded, {'+': altchars[0], '/': altchars[1]}) 

UnicodeEncodeError: 'ascii' codec can't encode character u'\xf8' in position 272: ordinal not in range(128) 

In [69]: response_dict['content'].encode('base64') 
--------------------------------------------------------------------------- 
UnicodeEncodeError      Traceback (most recent call last) 
C:\...\<ipython-input-69-7fd349f35f04> in <module>() 
----> 1 response_dict['content'].encode('base64') 

C:\...\base64_codec.pyc in base64_encode(input, errors) 
    22  """ 
    23  assert errors == 'strict' 
---> 24  output = base64.encodestring(input) 
    25  return (output, len(input)) 
    26 

C:\Python27\Lib\base64.pyc in encodestring(s) 
    313  for i in range(0, len(s), MAXBINSIZE): 
    314   chunk = s[i : i + MAXBINSIZE] 
--> 315   pieces.append(binascii.b2a_base64(chunk)) 
    316  return "".join(pieces) 
    317 

UnicodeEncodeError: 'ascii' codec can't encode character u'\xf8' in position 44: ordinal not in range(128) 

私は、これは少し意外な発見、248は符号なしバイト(の範囲内にあり、中に保持させることができるので、バイト文字列)が、私の本当の質問は:この文字列をエンコードするには、最適な方法は何ですか?

は私の現在の回避策はこれです:

In [74]: byte_string = ''.join(map(compose(chr, ord), response_dict['content'])) 

In [75]: byte_string[272] 
Out[75]: '\xf8' 

これは正常に動作しているように見えます、そして得られたbyte_stringは、base64でエンコードされることが可能であるが、より良い方法があるはずのように思えます。ある?

+1

248は、符号なしバイトの範囲内である可能性がありますが、標準化されたASCII [0-127]の範囲にはありません。 – Cameron

+0

@Cameron:真実で良い点ですが、バイト列に保持されたときとまったく同じ値がそのエラーにならないため、問題は説明されません。 – Marcin

+0

私の答えを参照してください:-)あなたがしたことは、 'unicode'文字列のコードポイントをとりバイトとして扱うことです。コードポイントが0〜255の範囲内にあるという保証はないので、これは最高です。さらに悪いことは、それがカスタムで未定義のエンコーディングであるため、後でバイト文字列をどのように解釈するかを誰も知らないことです。 – Cameron

答えて

2

バイナリデータを扱っているので、utf-8エンコーディングを使用することをお勧めします。私はそれがbase64でエンコードされた表現をどのように使用するのかに依存していると思います。私はあなたがユニコード文字列ではなくバイト文字列としてデータを取り出すことができれば、おそらくもっと良いと思います。私は要求ライブラリを使ったことが一度もありませんが、ドキュメントを閲覧することで可能であることが示唆されています。 「バイナリ・レスポンス・コンテンツ」と「未処理レスポンス・コンテンツ」に関するセクションがあります。

+0

ありがとう! latin-1というエンコーディングは、私の回避策とまったく同じバイト列を生成することが判明しました。 – Marcin

+1

@Marcin:リクエストモジュールが、テキストの操作、デフォルトエンコーディングの適用、およびバイナリデータのUnicodeへのデコードを想定していないことを確認する必要があります。そういう場合は問題がある。内容があなたが期待しているものであることを確認できますか? –

+2

ドキュメントにもっと注意を払っても、要求によってユニコードへの応答をデコードするために使用されるエンコードがわかります。したがって、常に確実にエンコードし直すことができますバイト)。 – Marcin

5

私は、base64エンコードの前にUTF-8のようなものにそれをコードする第一のことをお勧め:

In [12]: my_unicode = u'\xf8' 

In [13]: my_utf8 = my_unicode.encode('utf-8') 

In [15]: base64.b64encode(my_utf8) 
Out[15]: 'w7g=' 
+0

* UTF-8 *へのエンコーディングは意味をなさない。 UTF-8からbytes/asciiにエンコードするか、asciiからUTF-8にデコードします。それはもう一方の方法です。 – sebix

14

あなたはbase64でエンコードしたいunicode文字列を持っています。問題はb64encode()バイトでのみ動作し、の文字ではなく、で動作することです。したがって、文字列(抽象Unicodeコードポイントのシーケンス)をバイト文字列に変換する必要があります。

抽象的なUnicode文字列を具体的な一連のバイトにマッピングすることはと呼ばれます。 Pythonはいくつかのエンコーディングをサポートしています。

# Decode 
decoded = byte_string.decode('utf-8') 
:バイトをデコードしている誰でも意志も補完 decode()機能を経由して unicode文字列を取り戻すために使用されたエンコーディングを知る必要があることを

byte_string = response_dict['content'].encode('utf-8') 

注:私は、広く使用されているUTF-8エンコーディングを示唆します

ユニコードとエンコーディングの詳細については、Joel SpolskyのPython docsthis articleです。

+0

クリアする:私のユニコード文字列の内容はバイナリデータです。私はいくつかの異なるバイトにそれらを変更することはできません。 IDエンコーディングはありますか? – Marcin

+1

@Marcin:バイナリデータを含む 'unicode'文字列を持つことはできません。それは矛盾です! 'unicode'文字列のバイトがバイナリデータを表すと仮定した場合(ここのように見えます)、本当にUnicodeではないので、' unicode'オブジェクトに格納すべきではありません! – Cameron

+0

はい、それは私の問題です。 – Marcin

1

応答をバイナリバイトとして取得し、デコードおよびエンコードのステップを完全にスキップする必要があります。 requestsは、往復で何らかのデータやエラーを失うエンコードを選択する可能性が常にあります。

"Binary Response Content"と呼ばれるドキュメントのこの部分は、あなたの問題に完全に適合しているようです。

0

バイナリデータの場合...なぜエンコード/デコードするのですか?特に "base64.encodestring"部分。以下は、余分なファイルを持たずにPythonコードに直接追加するために、画像をbase64にエンコードする方法です。 2.7.2 btw

import base64 
iconfile = open("blah.icon","rb") 
icondata = iconfile.read() 
icondata = base64.b64encode(icondata) 
関連する問題