Base64 के साथ स्ट्रिंग को एनकोड करने के लिए मुझे 'b' की आवश्यकता क्यों है?


258

इस अजगर उदाहरण के बाद , मैं एक स्ट्रिंग के साथ Base64 को सांकेतिक शब्दों में बदलना है:

>>> import base64
>>> encoded = base64.b64encode(b'data to be encoded')
>>> encoded
b'ZGF0YSB0byBiZSBlbmNvZGVk'

लेकिन, अगर मैं अग्रणी को छोड़ दूं b:

>>> encoded = base64.b64encode('data to be encoded')

मुझे निम्नलिखित त्रुटि मिलती है:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python32\lib\base64.py", line 56, in b64encode
   raise TypeError("expected bytes, not %s" % s.__class__.__name__)
   TypeError: expected bytes, not str

ऐसा क्यों है?


37
वास्तव में सभी प्रश्न जो "TypeError: अपेक्षित बाइट्स, न कि str" के समान उत्तर देते हैं।
लेनार्ट रेगेब्रॉन

जवाबों:


273

बेस 64 एन्कोडिंग इसे इस्तेमाल करता है 8 बिट द्विआधारी बाइट डाटा और encodes लेता है केवल अक्षर A-Z, a-z, 0-9, +, /* तो यह चैनलों कि इस तरह के ईमेल के रूप में डेटा के सभी 8-बिट, की रक्षा नहीं करते तक भेजा जा सकता।

इसलिए, यह 8-बिट बाइट्स की एक स्ट्रिंग चाहता है। आप उन 3 को b''वाक्य रचना के साथ पायथन 3 में बनाते हैं ।

यदि आप bइसे हटाते हैं , तो यह एक स्ट्रिंग बन जाता है। एक स्ट्रिंग यूनिकोड वर्णों का एक क्रम है। बेस 64 में यूनिकोड डेटा के साथ क्या करना है इसका कोई पता नहीं है, यह 8-बिट नहीं है। यह वास्तव में किसी भी बिट्स नहीं है, वास्तव में। :-)

अपने दूसरे उदाहरण में:

>>> encoded = base64.b64encode('data to be encoded')

सभी वर्ण ASCII वर्ण सेट में बड़े करीने से फिट होते हैं, और बेस 64 एन्कोडिंग वास्तव में थोड़ा व्यर्थ है। आप इसे ascii में बदल सकते हैं, के साथ

>>> encoded = 'data to be encoded'.encode('ascii')

या सरल:

>>> encoded = b'data to be encoded'

जो इस मामले में एक ही बात होगी।


* अधिकांश बेस 64 फ्लेवर =में पैडिंग के रूप में अंत में शामिल हो सकते हैं । इसके अलावा, कुछ बेस 64 वैरिएंट के अलावा +और अन्य वर्णों का उपयोग कर सकते हैं /। अवलोकन के लिए विकिपीडिया पर वेरिएंट सारांश तालिका देखें ।


174

संक्षिप्त जवाब

आपको किसी bytes-likeऑब्जेक्ट ( bytesऔर bytearray, आदि) को base64.b64encode()विधि पर धकेलने की आवश्यकता है । यहाँ दो तरीके हैं:

>>> data = base64.b64encode(b'data to be encoded')
>>> print(data)
b'ZGF0YSB0byBiZSBlbmNvZGVk'

या एक चर के साथ:

>>> string = 'data to be encoded'
>>> data = base64.b64encode(string.encode())
>>> print(data)
b'ZGF0YSB0byBiZSBlbmNvZGVk'

क्यों?

पायथन 3 में, strऑब्जेक्ट सी-स्टाइल कैरेक्टर एरेज़ नहीं हैं (इसलिए वे बाइट एरेज़ नहीं हैं ), बल्कि, वे डेटा स्ट्रक्चर्स हैं, जिनमें कोई अंतर्निहित एन्कोडिंग नहीं है। आप विभिन्न तरीकों से उस स्ट्रिंग (या उसकी व्याख्या कर सकते हैं) को एनकोड कर सकते हैं। सबसे आम (और पायथन 3 में डिफ़ॉल्ट) utf-8 है, खासकर जब से यह ASCII के साथ पीछे की ओर संगत है (हालांकि, जैसा कि सबसे व्यापक रूप से उपयोग किए गए एनकोडिंग हैं)। ऐसा तब होता है जब आप एक stringकॉल करते हैं और कॉल करते हैं.encode() पर विधि को : पायथन स्ट्रिंग को utf-8 (डिफ़ॉल्ट एन्कोडिंग) में व्याख्या कर रहा है और आपको बाइट्स की सरणी प्रदान करता है जो इसके अनुरूप है।

बेस -64 पायथन 3 में एनकोडिंग

मूल रूप से प्रश्न शीर्षक ने बेस -64 एनकोडिंग के बारे में पूछा। बेस -64 सामान के लिए आगे पढ़ें।

base64एन्कोडिंग 6-बिट बाइनरी विखंड लेता है और उन्हें AZ, az, 0-9, '+', '/', और '=' वर्णों का उपयोग करके एन्कोड करता है (कुछ एनकोडिंग '+' और '/' के स्थान पर विभिन्न वर्णों का उपयोग करते हैं) । यह एक कैरेक्टर एन्कोडिंग है जो कि मूलांक -64 या बेस -64 नंबर सिस्टम के गणितीय निर्माण पर आधारित है, लेकिन वे बहुत अलग हैं। गणित में आधार -64 द्विआधारी या दशमलव जैसी एक संख्या प्रणाली है, और आप मूलांक के इस परिवर्तन को पूरी संख्या पर करते हैं, या (यदि आप जिस मूलांक से परिवर्तित कर रहे हैं वह 64 से कम 2 की शक्ति है) दाईं ओर से विखंडू में बाएं।

में base64एन्कोडिंग, अनुवाद बाएं से दाएं किया जाता है; वे पहले 64 वर्ण हैं, इसलिए इसे एन्कोडिंग कहा जाता हैbase64 । 65 वें '=' ​​चिह्न का उपयोग पैडिंग के लिए किया जाता है, क्योंकि एन्कोडिंग 6-बिट चंक को खींचती है, लेकिन आमतौर पर इसे एन्कोड करने के लिए डेटा 8-बिट बाइट्स होते हैं, इसलिए कभी-कभी अंतिम चंक में केवल दो या 4 बिट होते हैं।

उदाहरण:

>>> data = b'test'
>>> for byte in data:
...     print(format(byte, '08b'), end=" ")
...
01110100 01100101 01110011 01110100
>>>

यदि आप द्विआधारी डेटा को एक पूर्णांक के रूप में व्याख्या करते हैं, तो यह है कि आप इसे बेस -10 और बेस -64 ( बेस -64 के लिए तालिका ) में कैसे बदलेंगे :

base-2:  01 110100 011001 010111 001101 110100 (base-64 grouping shown)
base-10:                            1952805748
base-64:  B      0      Z      X      N      0

base64 एन्कोडिंग , हालांकि, इस डेटा को इस प्रकार फिर से समूहित करेगा:

base-2:  011101  000110  010101 110011 011101 00(0000) <- pad w/zeros to make a clean 6-bit chunk
base-10:     29       6      21     51     29      0
base-64:      d       G       V      z      d      A

तो, 'B0ZXN0' हमारे द्विआधारी, गणितीय रूप से बोलने का आधार -64 संस्करण है। हालांकि, base64 एन्कोडिंग को विपरीत दिशा में एन्कोडिंग करना पड़ता है (इसलिए कच्चे डेटा को 'dGVzdA' में बदल दिया जाता है) और अन्य अनुप्रयोगों को यह बताने का भी नियम है कि अंत में कितनी जगह बची है। यह '=' प्रतीकों के साथ अंत पैडिंग द्वारा किया जाता है। ऐसाbase64 इस डेटा का एन्कोडिंग 'dGVzdA ==' है, जिसमें दो 'बिट्स' को दर्शाने के लिए दो '=' प्रतीकों के साथ अंत से हटाए जाने की आवश्यकता होगी जब यह डेटा मूल डेटा से मेल खाने के लिए डिकोड हो जाता है।

आइए यह देखने के लिए परीक्षण करें कि क्या मैं बेईमान हूं:

>>> encoded = base64.b64encode(data)
>>> print(encoded)
b'dGVzdA=='

base64एन्कोडिंग का उपयोग क्यों करें ?

मान लीजिए कि मुझे ईमेल के माध्यम से किसी को कुछ डेटा भेजना है, जैसे कि यह डेटा:

>>> data = b'\x04\x6d\x73\x67\x08\x08\x08\x20\x20\x20'
>>> print(data.decode())

>>> print(data)
b'\x04msg\x08\x08\x08   '
>>>

मेरे द्वारा लगाए गए दो समस्याएं हैं:

  1. अगर मैंने उस ईमेल को यूनिक्स में भेजने का प्रयास किया, तो \x04चरित्र पढ़ते ही ईमेल भेज दिया जाएगा , क्योंकि वह END-OF-TRANSMISSION(Ctrl-D) के लिए ASCII है , इसलिए शेष डेटा ट्रांसमिशन से बाहर रह जाएगा।
  2. जब मैं डेटा को सीधे प्रिंट करता हूं, तो जब पायथन मेरे सभी बुरे नियंत्रण पात्रों से बचने के लिए पर्याप्त स्मार्ट होता है, जब उस स्ट्रिंग को ASCII के रूप में डिकोड किया जाता है, तो आप देख सकते हैं कि 'संदेश' नहीं है। ऐसा इसलिए है क्योंकि मैंने 'msg' को मिटाने के लिए तीन BACKSPACEवर्णों और तीन SPACEवर्णों का उपयोग किया है । इस प्रकार, यहां तक ​​कि अगर मेरे पास EOFचरित्र नहीं था, तो अंतिम उपयोगकर्ता स्क्रीन पर पाठ से वास्तविक, कच्चे डेटा में अनुवाद करने में सक्षम नहीं होगा।

यह केवल यह दिखाने के लिए एक डेमो है कि केवल कच्चे डेटा को भेजना कितना कठिन हो सकता है। बेस 64 प्रारूप में डेटा को एन्कोड करने से आपको सटीक डेटा मिलता है लेकिन एक प्रारूप में यह सुनिश्चित करता है कि यह ईमेल जैसे इलेक्ट्रॉनिक मीडिया पर भेजने के लिए सुरक्षित है।


6
base64.b64encode(s.encode()).decode()बहुत पाइथोनिक नहीं है जब आप चाहते हैं कि एक स्ट्रिंग से स्ट्रिंग रूपांतरण हो। base64.encode(s)कम से कम python3 में पर्याप्त होना चाहिए। अजगर में स्ट्रिंग्स और बाइट्स के बारे में बहुत अच्छी व्याख्या के लिए धन्यवाद
मोर्टेनबेल

2
@MortenB हाँ, यह अजीब है, लेकिन उल्टा बहुत स्पष्ट है कि क्या हो रहा है जब तक कि इंजीनियर बाइट्स और स्ट्रिंग्स के सरणियों के बीच के अंतर के बारे में जानते हैं, क्योंकि उनके बीच एक मैपिंग (एन्कोडिंग) नहीं है, अन्य भाषाओं के रूप में मान लीजिये।
ग्रेग Schmit

3
@MortenB वैसे, base64.encode(s)Python3 में काम नहीं करेगा; क्या आप कह रहे हैं कि ऐसा कुछ उपलब्ध होना चाहिए? मुझे लगता है कि यह भ्रमित करने वाला कारण हो सकता है कि एन्कोडिंग और स्ट्रिंग की सामग्री के आधार पर, sबाइट्स के एक सरणी के रूप में 1 अद्वितीय प्रतिनिधित्व नहीं हो सकता है।
ग्रेग स्मिट

श्मिट: यह सिर्फ एक उदाहरण था कि यह कितना सरल होना चाहिए। सबसे आम usecases उस तरह होना चाहिए।
मोर्टेनब

1
@MortenB लेकिन b64 सिर्फ टेक्स्ट के लिए ही नहीं है, किसी भी बाइनरी कंटेंट को b64 एन्कोडेड किया जा सकता है (ऑडियो, इमेज आदि)। जैसा कि आप मेरी राय में प्रस्तावित करते हैं, यह काम करना पाठ और बाइट सरणी के बीच के अंतर को और भी अधिक छुपा देता है, जिससे डिबगिंग कठिन हो जाती है। यह बस कठिनाई को कहीं और ले जाता है।
माइकल एको

32

यदि एन्कोड किए जाने वाले डेटा में "विदेशी" वर्ण हैं, तो मुझे लगता है कि आपको "UTF-8" में एनकोड करना होगा

encoded = base64.b64encode (bytes('data to be encoded', "utf-8"))

24

यदि स्ट्रिंग यूनिकोड है तो सबसे आसान तरीका है:

import base64                                                        

a = base64.b64encode(bytes(u'complex string: ñáéíóúÑ', "utf-8"))

# a: b'Y29tcGxleCBzdHJpbmc6IMOxw6HDqcOtw7PDusOR'

b = base64.b64decode(a).decode("utf-8", "ignore")                    

print(b)
# b :complex string: ñáéíóúÑ

वास्तव में सबसे आसान तरीका नहीं है, लेकिन सबसे स्पष्ट तरीकों में से एक है, जब यह महत्वपूर्ण है कि कौन सा एन्कोडिंग स्ट्रिंग को प्रसारित करने के लिए उपयोग किया जाता है, जो बेस 64 के माध्यम से डेटा ट्रांसमिशन के "प्रोटोकॉल" का हिस्सा है।
xuiqzy

12

आप सभी की जरूरत है:

expected bytes, not str

अग्रणी bआपके स्ट्रिंग बाइनरी बनाता है।

आप पायथन के किस संस्करण का उपयोग करते हैं? 2. x या 3. x?

संपादित करें: देखें http://docs.python.org/release/3.0.1/whatsnew/3.0.html#text-vs-data-instead-of-unicode-vs-8-bit Python में तार के गैरी विवरण के लिए 3.x


धन्यवाद मैं का उपयोग कर रहा हूँ, 3.x. पाइथन क्यों इसे द्विआधारी में बदलना चाहता है। रूबी में भी यही होगा ... आवश्यकता है> "बेस 64" और फिर> बेस 64.encode64 ('डेटा एनकोडेड')
डब्लिनटेक

2
@ डब्लिनटेक क्योंकि (यूनिकोड) पाठ कच्चे डेटा से अलग है। यदि आप बेस 64 में एक टेक्स्ट स्ट्रिंग को एनकोड करना चाहते हैं, तो पहले आपको वर्ण एन्कोडिंग (जैसे UTF-8) को निर्धारित करने की आवश्यकता है और फिर आपके पास वर्णों के बजाय बाइट्स हैं, जो कि आप टेक्स्ट एस्की-सुरक्षित रूप में एन्कोड कर सकते हैं।
फोरट्रान

2
इस सवाल का जवाब नहीं है। वह जानता है कि यह एक बाइट ऑब्जेक्ट के साथ काम करता है, लेकिन एक स्ट्रिंग ऑब्जेक्ट नहीं। सवाल यह है कि क्यों
लेन्नर्ट रेगेब्रॉन

@fortran Default Python3 स्ट्रिंग एन्कोडिंग UTF है, पता नहीं क्यों इसे स्पष्ट रूप से सेट करना पड़ता है।
xmedeko

0

इसका मतलब बस यह है कि आप इनपुट को बाइट्स या बाइट्स के रूप में ले रहे हैं, स्ट्रिंग के रूप में नहीं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.