2017-03-19 8 views
6

को Python2 में:एक ही स्ट्रिंग के साथ python2 और python3 में प्रिंट का आउटपुट क्यों अलग है?

$ python2 -c 'print "\x08\x04\x87\x18"' | hexdump -C 
00000000 08 04 87 18 0a         |.....| 
00000005 

python3 में:

$ python3 -c 'print("\x08\x04\x87\x18")' | hexdump -C 
00000000 08 04 c2 87 18 0a         |......| 
00000006 

क्यों बाइट "\xc2" यहाँ है?

संपादित:

मुझे लगता है कि जब स्ट्रिंग एक गैर- ASCII कैरेक्टर है, python3 स्ट्रिंग के लिए बाइट "\xc2" संलग्न कर देगा। (जैसा कि @ आश्रफुल इस्लाम ने कहा)

तो मैं इसे Python3 में कैसे टाल सकता हूं?

+0

कोई अन्य उदाहरण? क्या आप एक पैटर्न पा सकते हैं? –

उत्तर

9

निम्नलिखित स्निपेट पर विचार करें:

import sys 
for i in range(128, 256): 
    sys.stdout.write(chr(i)) 

भागो इस अजगर 2 के साथ और hexdump -C साथ परिणाम को देखने के:

00000000 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f |................| 

वगैरह। कोई आश्चर्य नहीं; 0x80 से 0xff से 128 बाइट्स।

अजगर 3 के साथ एक ही कार्य करें:

00000000 c2 80 c2 81 c2 82 c2 83 c2 84 c2 85 c2 86 c2 87 |................| 
... 
00000070 c2 b8 c2 b9 c2 ba c2 bb c2 bc c2 bd c2 be c2 bf |................| 
00000080 c3 80 c3 81 c3 82 c3 83 c3 84 c3 85 c3 86 c3 87 |................| 
... 
000000f0 c3 b8 c3 b9 c3 ba c3 bb c3 bc c3 bd c3 be c3 bf |................| 

संक्षेप में:

  • सब कुछ 0x80 से 0xbf करने के लिए 0xc2 prepended किया है।
  • 0xc0 से 0xff से सब कुछ शून्य 6 सेट शून्य है और 0xc3 प्रीपेड है।

तो, यहां क्या हो रहा है?

पायथन 2 में, तार ASCII हैं और कोई रूपांतरण नहीं किया जाता है। इसे 0-127 ASCII रेंज के बाहर कुछ लिखें, यह कहता है "ओकी-डॉक!" और बस उन बाइट्स लिखते हैं। सरल।

पायथन 3 में, तार यूनिकोड हैं। जब गैर-ASCII वर्ण लिखे गए हैं, तो उन्हें एन्कोडेड होना चाहिए। डिफ़ॉल्ट एन्कोडिंग यूटीएफ -8 है।

तो, ये मान यूटीएफ -8 में कैसे एन्कोड किए गए हैं? 0x80 से 0x7ff को

कोड अंक इस प्रकार इनकोड:

110vvvvv 10vvvvvv 

कहाँ 11 v वर्ण कोड बिंदु के टुकड़े कर रहे हैं।

इस प्रकार:

0x80     hex 
1000 0000   8-bit binary 
000 1000 0000  11-bit binary 
00010 000000   divide into vvvvv vvvvvv 
11000010 10000000 resulting UTF-8 octets in binary 
0xc2 0x80   resulting UTF-8 octets in hex 

0xc0     hex 
1100 0000   8-bit binary 
000 1100 0000  11-bit binary 
00011 000000   divide into vvvvv vvvvvv 
11000011 10000000 resulting UTF-8 octets in binary 
0xc3 0x80   resulting UTF-8 octets in hex 

तो यही कारण है कि आप 87 से पहले एक c2 हो रही है।

पायथन 3 में यह सब कैसे बचें? bytes प्रकार का उपयोग करें।

1

पायथन 2 का डिफ़ॉल्ट स्ट्रिंग प्रकार बाइट तार है। बाइट तार "abc" लिखा गया है जबकि यूनिकोड तार u"abc" लिखा गया है।

पायथन 3 का डिफ़ॉल्ट स्ट्रिंग प्रकार यूनिकोड तार है। बाइट तार b"abc" के रूप में लिखे गए हैं जबकि यूनिकोड स्ट्रिंग्स "abc" (u"abc" अभी भी काम करता है) लिखा गया है। चूंकि लाखों यूनिकोड वर्ण हैं, उन्हें बाइट्स के रूप में प्रिंट करने के लिए एक एन्कोडिंग (UTF-8 आपके मामले में) की आवश्यकता होती है जिसके लिए प्रति कोड बिंदु एकाधिक बाइट्स की आवश्यकता होती है।

पहले पायथन 3 प्रकार प्राप्त करने के लिए पायथन 3 में बाइट स्ट्रिंग का उपयोग करें। फिर, क्योंकि पाइथन 3 की print यूनिकोड तारों की अपेक्षा करता है, कच्चे स्टडआउट इंटरफ़ेस को लिखने के लिए sys.stdout.buffer.write का उपयोग करें, जो बाइट स्ट्रिंग की अपेक्षा करता है।

python3 -c 'import sys; sys.stdout.buffer.write(b"\x08\x04\x87\x18")' 

ध्यान दें कि एक फ़ाइल के लिए लिख अगर, वहाँ इसी तरह के मुद्दों कर रहे हैं। कोई एन्कोडिंग अनुवाद के लिए, बाइनरी मोड 'wb' में फ़ाइलें खोलें और बाइट स्ट्रिंग लिखें।

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