8

में यूनिकोड तार एन्कोडिंग मैं एक यूनिकोड स्ट्रिंग का उपयोग एक वेब सेवा से लिया गया है requests module, जो (, पीसीएल के रूप में यह होता है) एक बाइनरी दस्तावेज़ की बाइट का है। इन बाइट्स में से एक मूल्य 248 है, और बेस 64 करने का प्रयास कर सांकेतिक शब्दों में बदलना यह निम्न त्रुटि की ओर जाता है:बेस 64 अजगर 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 की जा रही बेस 64 इनकोडिंग में सक्षम है, लेकिन ऐसा लगता है जैसे वहाँ एक बेहतर तरीका होना चाहिए। है?

+1

248 एक हस्ताक्षरित बाइट की सीमा के भीतर हो सकता है, लेकिन यह मानकीकृत ASCII [0-127] की सीमा में नहीं है। – Cameron

+0

@ कैमरॉन: एक सच्चा और अच्छा बिंदु, लेकिन यह अभी भी समस्या की व्याख्या नहीं करता है, क्योंकि बाइट स्ट्रिंग में होने पर सटीक समान मान उस त्रुटि का परिणाम नहीं देता है। – Marcin

+0

मेरा उत्तर देखें :-) आपने जो किया है वह 'यूनिकोड' स्ट्रिंग के कोडपॉइंट्स लेता है और उन्हें बाइट्स के रूप में व्यवहार करता है। यह ... सबसे अच्छा है, क्योंकि आप की कोई गारंटी नहीं है कि कोडपॉइंट 0-255 की सीमा के भीतर भी हैं। इससे भी बदतर यह है कि किसी और को यह पता नहीं चलेगा कि बाइट स्ट्रिंग को बाद में कैसे समझना है, क्योंकि यह एक कस्टम, अपरिभाषित एन्कोडिंग में है। – Cameron

उत्तर

2

चूंकि आप बाइनरी डेटा के साथ काम कर रहे हैं, मुझे यकीन नहीं है कि utf-8 एन्कोडिंग का उपयोग करना एक अच्छा विचार है। मुझे लगता है कि यह इस बात पर निर्भर करता है कि आप बेस 64 एन्कोडेड प्रतिनिधित्व का उपयोग कैसे करना चाहते हैं। मुझे लगता है कि यह संभवतः बेहतर होगा यदि आप डेटा को बाइट स्ट्रिंग के रूप में पुनर्प्राप्त कर सकते हैं, न कि यूनिकोड स्ट्रिंग। मैंने अनुरोध पुस्तकालय का कभी भी उपयोग नहीं किया है, लेकिन दस्तावेज़ीकरण ब्राउज़ करने से पता चलता है कि यह संभव है। "बाइनरी प्रतिक्रिया सामग्री" और "कच्चे प्रतिक्रिया सामग्री" के बारे में बात कर रहे अनुभाग हैं।

+0

धन्यवाद! यह पता चला है कि लैटिन -1 के रूप में एन्कोडिंग मेरे वर्कअराउंड के रूप में बाइट्स के सटीक समान अनुक्रम उत्पन्न करता है। – Marcin

+1

@ मार्सिन: आपको यह सुनिश्चित करने की ज़रूरत है कि अनुरोध मॉड्यूल ने यह नहीं माना है कि आप टेक्स्ट के साथ काम कर रहे हैं, एक डिफ़ॉल्ट एन्कोडिंग लागू किया है, और अपने बाइनरी डेटा को यूनिकोड में डीकोड किया है। अगर ऐसा है तो आपको परेशानी हो रही है। क्या आप यह सत्यापित कर सकते हैं कि सामग्री आप क्या उम्मीद करते हैं? –

+2

दस्तावेज़ों पर थोड़ा अधिक ध्यान देने के बाद, यह पता चला है कि अनुरोध मुझे एन्कोडिंग के बारे में बताते हैं जो यूनिकोड के जवाब को डीकोड करने के लिए उपयोग किया जाता है, इसलिए मैं हमेशा इसके साथ फिर से एन्कोड कर सकता हूं (और यह एक बार फिर से उत्पन्न होता है बाइट्स)। – Marcin

5

मैं पहली बार यह UTF-8 की तरह कुछ करने के लिए एन्कोडिंग base64 एन्कोडिंग से पहले सुझाव है:

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

* यूटीएफ -8 * को एन्कोडिंग समझ में नहीं आता है। या तो आप यूटीएफ -8 से बाइट्स/एएससीआई में एन्कोड करते हैं या आप एसीआईआई से यूटीएफ -8 तक डीकोड करते हैं। यह दूसरा रास्ता है। – sebix

14

आप एक unicode स्ट्रिंग जो आप बेस 64 एन्कोड करना चाहते हैं। समस्या यह है कि b64encode() केवल बाइट्स पर काम करता है, वर्ण पर नहीं। इसलिए, आपको अपने unicode स्ट्रिंग (जो सार यूनिकोड कोडपॉइंट्स का अनुक्रम है) को बाइट स्ट्रिंग में बदलने की आवश्यकता है।

बाइट्स की एक ठोस श्रृंखला में अमूर्त यूनिकोड तारों का मानचित्रण एन्कोडिंग कहा जाता है। पायथन कई एन्कोडिंग का समर्थन करता है;

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

ध्यान दें कि जो कोई भी बाइट डिकोडिंग है यह भी जानना चाहते कि कौन सी एन्कोडिंग पूरक decode() समारोह के माध्यम से एक unicode स्ट्रिंग वापस पाने के लिए इस्तेमाल किया गया था की आवश्यकता होगी::

# Decode 
decoded = byte_string.decode('utf-8') 
मैं व्यापक रूप से इस्तेमाल UTF-8 एन्कोडिंग का सुझाव

यूनिकोड और एन्कोडिंग के बारे में अधिक जानने के लिए एक अच्छा प्रारंभिक बिंदु Python docs, और this article जोएल स्पॉल्स्की द्वारा है।

+0

स्पष्ट होने के लिए: मेरी यूनिकोड स्ट्रिंग की सामग्री बाइनरी डेटा हैं। मैं उन्हें कुछ अलग बाइट्स में नहीं बदल सकता। क्या कोई पहचान एन्कोडिंग है? – Marcin

+1

@ मार्सिन: आपके पास बाइनरी डेटा युक्त 'यूनिकोड' स्ट्रिंग नहीं हो सकती है। यह शब्दों में एक विरोधाभास है! यदि 'यूनिकोड' स्ट्रिंग के बाइट्स को बाइनरी डेटा (जैसा कि यहां मामला लगता है) का प्रतिनिधित्व करना है, तो इसे 'यूनिकोड' ऑब्जेक्ट में संग्रहीत नहीं किया जाना चाहिए क्योंकि यह वास्तव में यूनिकोड नहीं है! – Cameron

+0

हाँ, यह मेरी समस्या है। – Marcin

1

बाइनरी बाइट्स के रूप में प्रतिक्रिया प्राप्त करना और डिकोडिंग और एन्कोडिंग चरणों को पूरी तरह से छोड़ना संभव होना चाहिए। हमेशा एक संभावना है कि requests एक एन्कोडिंग चुनेंगे जो राउंड ट्रिप में कुछ डेटा या त्रुटियों को खो देता है।

"Binary Response Content" नामक दस्तावेज़ों का यह हिस्सा आपकी समस्या को पूरी तरह फिट करने लगता है।

0

यदि यह बाइनरी डेटा है ... क्यों एन्कोड/डीकोड बिल्कुल? विशेष रूप से "base64.encodestring" भाग।नीचे यह है कि मैं अतिरिक्त फाइलों के बजाय सीधे अपने पायथन कोड में जोड़ने के लिए छवियों को बेस 64 में कैसे एन्कोड करता हूं। 2.7.2 बीटीडब्ल्यू

import base64 
iconfile = open("blah.icon","rb") 
icondata = iconfile.read() 
icondata = base64.b64encode(icondata) 
संबंधित मुद्दे