2012-04-04 10 views
9

मैं इस शर्मनाक आसान लग रहा है, और मुझे लगता है कि समस्या मैं सिर्फ यह सब बाइट्स-str-यूनिकोड की स्पष्ट समझ की जरूरत नहीं है कि है (और एन्कोडिंग-डिकोडिंग, स्पष्ट रूप से बोलते हुए) सामान अभी तक।डिकोड base64 स्ट्रिंग अजगर 3 में (lxml साथ हो या नहीं)

मैं अपने काम कोड को पायथन 3 पर चलाने की कोशिश कर रहा हूं। जिस भाग में मैं फंस गया हूं वह है जब मैं lxml के साथ एक एक्सएमएल पार्स करता हूं और उस एक्सएमएल में बेस 64 स्ट्रिंग को डीकोड करता हूं।

कोड अब निम्नलिखित तरीके से काम करता है:

मैं एक XPath क्वेरी '.../binary/text()' साथ बाइनरी डेटा पुनः प्राप्त। यह एक-तत्व सूची बनाता है जिसमें lxml.etree._ElementUnicodeResult ऑब्जेक्ट होता है।

decoded = source.decode('base64') 

और अंत में

output = numpy.frombuffer(decoded) 

हालांकि, अजगर 3 पर मैं

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

कह यह ऐसा नहीं है एक त्रुटि संदेश मिलता: तो फिर, अजगर 2 के साथ, मैं ऐसा करने में सक्षम था आश्चर्यजनक, क्योंकि lxml.etree._ElementUnicodeResultstr का उप-वर्ग है।

एक और तरीका है

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

कि मूलतः एक ही होगा साथ उस में एक ही डेटा के साथ एक वास्तविक str प्राप्त करने के लिए किया जाएगा। तो मैं इसे बेस 64 से डीकोड करने के लिए क्या करूं? मैं base64 मॉड्यूल को देखा है, लेकिन यह एक तर्क के रूप में एक bytes वस्तु लेता है, और मैं जिस तरह से bytes के रूप में पेश करने के लिए str के बारे में सोच नहीं सकते, क्योंकि अगर मैं एक bytes वस्तु का निर्माण करने की कोशिश करते हैं, अजगर एनकोड करने की कोशिश करेंगे स्ट्रिंग, जिसकी मुझे आवश्यकता नहीं है।

आगे Googling, मैं (जो वैसे भी base64 से परोक्ष रूप से उत्पन्न होता है, अगर मैं गलत नहीं हूँ) binascii मॉड्यूल भर में आया था, लेकिन मेरे स्ट्रिंग पर binascii.b2a_base64() बुला

TypeError: 'str' does not support the buffer interface 

पी एस का उत्पादन मुझे how to decode a hex string in Python 3 पर एक उत्तर प्रश्न भी मिला है, लेकिन यह एक समर्पित विधि bytes.fromhex() के साथ किया गया है, इसलिए मुझे नहीं लगता कि यह कैसे सहायक होगा।

क्या कोई मुझे बता सकता है कि मुझे क्या याद आ रही है? मुझे डर है कि अधिकांश पोस्ट अप्रासंगिक है और केवल मेरी शर्मिंदगी को बढ़ा देती है, लेकिन कम से कम आप लोग what I tried जानते हैं।

+4

पर एक unicode वस्तु वापस आ जाएगी एक के रूप में, नेड Batchelder इस बाइट्स-str-यूनिकोड सामान पर एक महान प्रस्तुति है: [व्यावहारिक यूनिकोड, या: मैं दर्द को कैसे रोकूं?] (Http://nedbatchelder.com/text/unipain.html) – delnan

+0

धन्यवाद @ डेलनान, मैं आधे रास्ते से हूं और वास्तव में बहुत पहले से मदद करता हूं :) –

उत्तर

2

मेरे पास पाइथन 3 स्थापित नहीं है, लेकिन ऐसा लगता है कि आपको यूनिकोड को एलएक्सएमएल से बाइट्स में वापस करने की आवश्यकता है, शायद .encode ('ascii') को कॉल करके?

+0

गोश ... मुझे पता था कि यह आसान था। मैं इस सामान को अपने दिमाग में इस तरह से व्यवस्थित नहीं कर सकता हूं। मैं अपनी स्ट्रिंग के बारे में कुछ * एन्कोडेड * के बारे में सोच रहा हूं, इसलिए यह वास्तव में मेरे लिए नहीं हुआ कि मुझे इसे 'बाइट्स' प्राप्त करने के लिए एन्कोड करने की आवश्यकता है। धन्यवाद। –

+3

यूनिकोड को सादे-वेनिला-तारों के रूप में सोचें जिन्हें "हार्डवेयर" पर जाने पर डीकोड किया जाना चाहिए और "हार्डवेयर" से आने पर डीकोड किया जाना चाहिए :-) – thebjorn

+0

मुझे लगा कि इस तरह के लंबे प्रश्न की आवश्यकता लंबे समय तक की आवश्यकता है, लेकिन वैसे भी , सही दिशा को इंगित करने के लिए बहुत धन्यवाद :) –

6

ठीक है, मुझे लगता है कि मैं चीजों की मेरी वर्तमान समझ को सारांशित करने जा रहा हूं (मुझे सही करने के लिए स्वतंत्र महसूस करें)। उम्मीद है कि यह किसी और की मदद करेगा क्योंकि मैं उलझन में हूं।

क्रेडिट पूरी तरह से thebjorn और delnan पर जाता है।

तो, सबसे सामान्य चीजों से शुरू: Unicode है, और यह एक वैश्विक मानक है जो उन सभी विदेशी पात्रों को कोड (या कोड पॉइंट) निर्दिष्ट करता है जिन्हें आप कल्पना कर सकते हैं। वे कोड केवल पूर्णांक संख्याएं हैं। विकिपीडिया कहते हैं, यूनिकोड 6.1 के अनुसार 109, 9 75 ग्राफिक वर्ण हैं।

फिर एन्कोडिंग हैं जो परिभाषित करती हैं कि यूनिकोड वर्णों को बाइट कोड के साथ कैसे नामित किया जाए। एक बाइट एक मनमाना यूनिकोड चार नामित करने के लिए पर्याप्त नहीं है। हालांकि, यदि आप केवल उनमें से एक छोटा सबसेट लेते हैं (अंग्रेजी वर्णमाला, अंक, विराम चिह्न, कुछ नियंत्रण वर्ण), तो आप एक बाइट प्रति चरित्र (या यहां तक ​​कि 7 बिट्स; ASCII देखें) के साथ कर सकते हैं।


एक यूनिकोड स्ट्रिंग कहीं भी पारित करने के लिए, एक, बाइट में यह सांकेतिक शब्दों में बदलना करने की जरूरत है तो यह दूसरे छोर पर डीकोड किया जा सकता।

पायथन 2, str वास्तव में बाइट्स है, और unicode यूनिकोड है, लेकिन पाइथन 2 आवश्यक होने पर आपके लिए निहित एन्कोडिंग/डिकोडिंग करेगा। यह ASCII एन्कोडिंग का उपयोग करने का प्रयास करेगा।

पायथन 3, str में हमेशा एक यूनिकोड स्ट्रिंग है, और bytes वास्तविक बाइट्स के लिए एक नया डेटा प्रकार है। पाइथन 3 द्वारा कोई अंतर्निहित रूपांतरण कभी नहीं किया जाता है, आपको हमेशा इसे स्वयं करने और एन्कोडिंग निर्दिष्ट करने की आवश्यकता होती है। इसका मतलब यह है कि आपका प्रोग्राम तब तक काम नहीं करेगा जब तक कि आप समझ न सकें कि क्या हो रहा है, जो पूरी तरह से मेरे साथ हुआ।


अब, यह कम या ज्यादा स्पष्ट किया जा रहा है, के base64 एन्कोडिंग है, जो भी तरह की कोई एन्कोडिंग है, लेकिन एक अलग अर्थ नहीं है पर चलते हैं। मान लें कि आपके पास कुछ बाइनरी डेटा है (यानी बाइट्स) जिसका अर्थ कुछ भी हो सकता है (मेरे मामले में यह float एस का समूह है)। अब आप एक स्ट्रिंग के साथ इस बाइनरी सरणी का प्रतिनिधित्व करना चाहते हैं। बेस 64 एन्कोडिंग का यही अर्थ है: आपके पास अपने बाइट्स को ASCII स्ट्रिंग के रूप में दर्शाया गया है।

बेस 64 का मतलब 6 बिट है, इसलिए बेस 64-एन्कोडेड स्ट्रिंग में एक वर्ण आपके डेटा के 6 बिट्स के लिए है। यही कारण है कि बेस 64-एन्कोडेड स्ट्रिंग्स की लंबाई लंबाई 4 है जो कि 4 से अधिक है: अन्यथा एन्कोड किए गए बाइट्स की संख्या पूर्णांक नहीं होगी।


अंत में, बेस 64 से डीकोड करने के लिए आपको एक ASCII स्ट्रिंग की आवश्यकता है। एक यूनिकोड स्ट्रिंग नहीं करेगी, केवल बेस 64 वर्णमाला से वर्ण हो सकते हैं। Base64 module पायथन में नौकरी करता है। base64.b64decode() फ़ंक्शन तर्क के रूप में बाइट स्ट्रिंग लेता है। पायथन 2 में इसका अर्थ है: str। पायथन 3 में इसका अर्थ है: bytes। तो अगर आप एक str, जैसे

>>> s = 'U3RhY2sgT3ZlcmZsb3c=' 

अजगर 2 में है तुम सिर्फ कर सकता है

>>> s.decode('base64') 

क्योंकि s ASCII में पहले से ही है। ,

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

और जिस तरह से, यह एक bytes वस्तु वापस आ जाएगी तो यह वास्तव में आप कैसे पर निर्भर है: अजगर 3 में, आप यह एनकोड करने के लिए ASCII में, जरूरत है पहले तो आप करना होगा तब उन बाइट्स का इलाज करने के लिए।शायद यह मेरी फ्लोट है, लेकिन शायद आपको इसे ASCII के रूप में डीकोड करने का प्रयास करना चाहिए :) पायथन 2 में हालांकि यह केवल str होगा। वैसे भी, उन बाइट्स से अपने डेटा को अनपैक करने के लिए टूल के लिए struct पर एक नज़र डालें।

तो यदि आपको पाइथन 2 और 3 दोनों पर काम करने के लिए कोड की आवश्यकता है, तो अंतिम के साथ जाएं। आप अंत में यूनिकोड है (यदि आप बेस 64 से पाठ डिकोड कर रही हैं) यह सुनिश्चित करने के लिए, आप इसे डिकोड करने के लिए होगा:

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

अजगर 2 पर, क्योंकि यह str पर लागू की गई encode('ascii') प्रभावी रूप से कुछ नहीं करेंगे । तो यह अंतर्निहित रूपांतरण पहले यूनिकोड में करेगा, और उसके बाद आप जो चाहते हैं उसे करें (इसे वापस ASCII में परिवर्तित करें)। decode('ascii') अलग अजगर 2.

+0

उत्कृष्ट सारांश :-) यदि आप फ्लोट की सूची सहेजने की कोशिश कर रहे हैं, तो शायद स्ट्रक्चर मॉड्यूल स्ट्रक्चर मॉड्यूल से आसान होगा? Base64.b64encode की तरह कुछ (pickle.dumps ([2.718, 3.141])) – thebjorn

+0

@thebjorn धन्यवाद :) मैं वास्तव में 'numpy.frombuffer() 'का उपयोग कर रहा हूं, मैंने संदर्भ के लिए' संरचना 'का उल्लेख किया है, सामान्य के लिए मामला। –

+0

"आपका प्रोग्राम तब तक काम नहीं करेगा जब तक कि आप समझें कि क्या हो रहा है" - यह एक अच्छी बात है, ज्यादातर समय। :) – AKX

संबंधित मुद्दे