2010-11-24 18 views
10

में मैं एक आवेदन है कि लौटने के लिए उत्सुक लगता है के खिलाफ काम कर रहा हूँ, कि मैं क्या, डबल UTF-8 एन्कोडेड तार होने के लिए विश्वास करते हैं।डबल-डिकोडिंग यूनिकोड अजगर

मैं यूटीएफ -8 का उपयोग करके एन्कोडेड स्ट्रिंग u'XüYß' भेजता हूं, इस प्रकार X\u00fcY\u00df (X\xc3\xbcY\xc3\x9f के बराबर) बनता है।

सर्वर चाहिए बस गूंज मैं इसे क्या भेजा है, अभी तक रिटर्न निम्नलिखित: X\xc3\x83\xc2\xbcY\xc3\x83\xc2\x9f (X\xc3\xbcY\xc3\x9f होना चाहिए)। अगर मैं का उपयोग कर इसे डिकोड str.decode('utf-8')u'X\xc3\xbcY\xc3\x9f' जो, एक ... यूनिकोड स्ट्रिंग की तरह दिखता है UTF-8 का उपयोग कर इनकोडिंग मूल स्ट्रिंग वाली हो जाता है,।

लेकिन अजगर मुझे यह पहली बार फिर से एन्कोडिंग के बिना एक यूनिकोड स्ट्रिंग डिकोड नहीं दूँगी - जो किसी कारण से विफल रहता है, कि मुझे निकल जाता है:

>>> ret = 'X\xc3\x83\xc2\xbcY\xc3\x83\xc2\x9f'.decode('utf-8') 
>>> ret 
u'X\xc3\xbcY\xc3\x9f' 
>>> ret.decode('utf-8') 
# Throws UnicodeEncodeError: 'ascii' codec can't encode ... 

मैं अजगर कैसे राजी करते स्ट्रिंग फिर से डिकोड करने के लिए ? - और/या क्या यह वास्तव में स्ट्रिंग्स में वास्तव में क्या है, इसे डिबग करने का कोई (व्यावहारिक) तरीका है, हालांकि सभी अंतर्निहित रूपांतरण print उपयोग करता है?

(और हाँ, मैं सर्वर साइड के डेवलपर्स के साथ इस व्यवहार सूचना दी है।)

उत्तर

19

ret.decode() की कोशिश करता परोक्ष साथ ret एन्कोड करने के लिए सिस्टम एन्कोडिंग - आपके मामले में ascii।

आप स्पष्ट रूप से यूनिकोड स्ट्रिंग सांकेतिक शब्दों में बदलना है, तो आप ठीक होना चाहिए।

>>> 'X\xc3\xbcY\xc3\x9f'.encode('raw_unicode_escape').decode('utf-8') 
'XüYß' 

वास्तव में, .encode('latin1') (या cp1252) ठीक हो सकता है, क्योंकि जो सर्वर लगभग cerainly उपयोग कर रहा है कि: वहाँ एक builtin एन्कोडिंग आपको क्या चाहिए करता है। raw_unicode_escape कोडेक केवल आपके अंत में कुछ पहचानने योग्य एक अपवाद को ऊपर उठाने के बजाय दे देंगे:

:

>>> '€\xe2\x82\xac'.encode('raw_unicode_escape').decode('utf8') 
'\\u20ac€' 

>>> '€\xe2\x82\xac'.encode('latin1').decode('utf8') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
UnicodeEncodeError: 'latin-1' codec can't encode character '\u20ac' in position 0: ordinal not in range(256) 

मामले में आप मिश्रित डेटा की इस तरह में चलाने, आप फिर से कोडेक का उपयोग कर सकते, सब कुछ सामान्य बनाने में

>>> '€\xe2\x82\xac'.encode('raw_unicode_escape').decode('utf8') 
'\\u20ac€' 

>>> '\\u20ac€'.encode('raw_unicode_escape') 
b'\\u20ac\\u20ac' 
>>> '\\u20ac€'.encode('raw_unicode_escape').decode('raw_unicode_escape') 
'€€' 
+0

** Whew ** - मेरी डरावनी चीज़ का उपयोग करने की आवश्यकता नहीं है। –

0

इसका उपयोग न करें!@hop's solution का उपयोग करें।

मेरे बुरा हैक: (चापलूसी लेकिन चुपचाप यह मेरी गलती नहीं है, यह सर्वर डेवलपर्स गलती है!।)

def double_decode_unicode(s, encoding='utf-8'): 
    return ''.join(chr(ord(c)) for c in s.decode(encoding)).decode(encoding) 
फिर

,

>>> double_decode_unicode('X\xc3\x83\xc2\xbcY\xc3\x83\xc2\x9f') 
u'X\xfcY\xdf' 
>>> print _ 
XüYß 
+0

वैसे भी महान प्रश्न। एक बुरा स्थिति। मुझे आशा है कि किसी और 'chr से एक neater समाधान (ord (ग)) के साथ आ सकते हैं', str को यूनिकोड में परिवर्तित वर्ण दर वर्ण के लिए ... –

+0

'च (चार) स्ट्रिंग' में चार के लिए एक एन्कोडिंग के लिए रोता है। – hop

+0

@hop: क्या यह करता है? ऐसा कैसे? –

1

क्या आप चाहते हैं एन्कोडिंग जहां यूनिकोड कोड बिंदु एक्स 0-255 अंदर कोड अंक के लिए एक ही बाइट मूल्य एक्स के लिए इनकोडिंग है आप लैटिन -1 एन्कोडिंग में यह है:

def double_decode(bstr): 
    return bstr.decode("utf-8").encode("latin-1").decode("utf-8") 
संबंधित मुद्दे