आप वास्तव में एक स्ट्रिंग के एन्कोडिंग के बारे में केवल तब सोचते हैं जब यह टूट जाती है। जब आप अपने एक्सेप्शन ट्रैकर की जांच करते हैं और देखते हैं
Encoding::InvalidByteSequenceError: "\xFE" on UTF-8
आपको घूर रहा है। या शायद "they're" "they’re" के रूप में दिखना शुरू हो जाता है।
तो, जब आपके पास खराब एन्कोडिंग होती है, तो आप कैसे पता लगाते हैं कि क्या टूटा? और आप इसे कैसे ठीक कर सकते हैं?
एन्कोडिंग क्या है?
अगर आप कल्पना कर सकते हैं कि एन्कोडिंग एक स्ट्रिंग के साथ क्या करता है, तो इन बग को ठीक करना आसान है।
आप एक स्ट्रिंग को बाइट्स की एक सरणी, या छोटी संख्याओं के रूप में सोच सकते हैं:
irb(main):001:0> "hello!".bytes => [104, 101, 108, 108, 111, 33]
इस एन्कोडिंग में, 104 का अर्थ h है, 33 का अर्थ ! है, और इसी तरह।
यह तब पेचीदा हो जाता है जब आप अंग्रेजी में कम आम वर्णों का उपयोग करते हैं:
irb(main):002:0> "hellṏ!".bytes => [104, 101, 108, 108, 225, 185, 143, 33]
अब यह बताना कठिन है कि कौन सी संख्या किस वर्ण को दर्शाती है। एक बाइट के बजाय, ṏ बाइट्स के समूह [225, 185, 143] द्वारा दर्शाया गया है। लेकिन बाइट्स और वर्णों के बीच अभी भी एक संबंध है। और एक स्ट्रिंग का एन्कोडिंग उस संबंध को परिभाषित करता है।
एक नज़र डालें कि बाइट्स का एक ही सेट कैसा दिखता है जब आप विभिन्न एन्कोडिंग आज़माते हैं:
# एक विशेष वर्ण के साथ ISO-8859-1 स्ट्रिंग आज़माएं! irb(main):003:0> str = "hellÔ!".encode("ISO-8859-1"); str.encode("UTF-8") => "hellÔ!" irb(main):004:0> str.bytes => [104, 101, 108, 108, 212, 33] # वही स्ट्रिंग ISO-8859-5 के रूप में व्याख्या करने पर कैसी दिखेगी? irb(main):005:0> str.force_encoding("ISO-8859-5"); str.encode("UTF-8") => "hellд!" irb(main):006:0> str.bytes => [104, 101, 108, 108, 212, 33]
बाइट्स नहीं बदलीं। लेकिन यह बिल्कुल सही नहीं दिखता। एन्कोडिंग बदलने से स्ट्रिंग का प्रिंट बदल गया, बिना बाइट्स बदले।
और सभी स्ट्रिंग्स को सभी एन्कोडिंग में दर्शाया नहीं जा सकता:
irb(main):006:0> "hi∑".encode("Windows-1252") Encoding::UndefinedConversionError: U+2211 to WINDOWS-1252 in conversion from UTF-8 to WINDOWS-1252 from (irb):61:in `encode' from (irb):61 from /usr/local/bin/irb:11:in `<main>'
अधिकांश एन्कोडिंग छोटी हैं, और हर संभव वर्ण को संभाल नहीं सकतीं। जब एक एन्कोडिंग में एक वर्ण दूसरी में मौजूद नहीं होता, या जब Ruby दो एन्कोडिंग के बीच एक वर्ण का अनुवाद नहीं कर पाता, तो आपको वह त्रुटि दिखाई देगी।
यदि आप encode में अतिरिक्त विकल्प पास करते हैं तो आप इस त्रुटि को हल कर सकते हैं:
irb(main):064:0> "hi∑".encode("Windows-1252", invalid: :replace, undef: :replace) => "hi?"
invalid और undef विकल्प उन वर्णों को एक अलग वर्ण से बदल देते हैं जिनका अनुवाद नहीं किया जा सकता। डिफ़ॉल्ट रूप से, वह प्रतिस्थापन वर्ण ? है। (जब आप यूनिकोड में परिवर्तित करते हैं, तो यह होता है)।
दुर्भाग्य से, जब आप encode के साथ वर्णों को ? से बदलते हैं, तो आप जानकारी खो सकते हैं। आपको पता नहीं चलेगा कि कौन से बाइट्स ? से बदले गए थे। लेकिन अगर आपको अपने डेटा को उस नई एन्कोडिंग में रखने की आवश्यकता है, तो डेटा खोना चीजों के टूटने से बेहतर हो सकता है।
अब तक, आपने एन्कोडिंग को समझने में मदद करने के लिए तीन प्रमुख स्ट्रिंग विधियां देखी हैं:
encode, जो एक स्ट्रिंग को दूसरी एन्कोडिंग में अनुवाद करता है (वर्णों को नई एन्कोडिंग में उनके समकक्ष में परिवर्तित करता है)bytes, जो आपको एक स्ट्रिंग को बनाने वाले बाइट्स दिखाएगाforce_encoding, जो आपको दिखाएगा कि वे बाइट्स एक अलग एन्कोडिंग द्वारा व्याख्या किए जाने पर कैसे दिखेंगे
encode और force_encoding के बीच प्रमुख अंतर यह है कि encode bytes को बदल सकता है, और force_encoding नहीं बदलेगा।
एन्कोडिंग बग ठीक करने के लिए तीन-चरणीय प्रक्रिया
आप अधिकांश एन्कोडिंग समस्याओं को तीन चरणों में ठीक कर सकते हैं:
1. पता करें कि आपकी स्ट्रिंग वास्तव में किस एन्कोडिंग में है।
यह आसान लगता है। लेकिन सिर्फ इसलिए कि एक स्ट्रिंग कहती है कि यह कुछ एन्कोडिंग है, इसका मतलब यह नहीं कि यह वास्तव में है:
irb(main):078:0> "hi\x99!".encoding => #<Encoding:UTF-8>
यह सही नहीं है - अगर यह वास्तव में UTF-8 होता, तो इसमें वह अजीब बैकस्लैश नंबर नहीं होता। तो आप अपनी स्ट्रिंग के लिए सही एन्कोडिंग कैसे पता लगाते हैं?
बहुत सारे पुराने सॉफ़्टवेयर एक डिफ़ॉल्ट एन्कोडिंग पर टिके रहेंगे, इसलिए आप शोध कर सकते हैं कि इनपुट कहां से आया। क्या किसी ने इसे Word से पेस्ट किया? यह Windows-1252 हो सकता है। क्या यह किसी फ़ाइल से आया या आपने इसे किसी पुरानी वेबसाइट से निकाला? यह ISO-8859-1 हो सकता है।
मुझे उन विकिपीडिया पृष्ठों पर लिंक की गई एन्कोडिंग तालिकाओं को खोजना भी उपयोगी लगा है। उन तालिकाओं पर, आप अज्ञात संख्याओं द्वारा संदर्भित वर्णों को देख सकते हैं, और देख सकते हैं कि वे संदर्भ में समझ में आते हैं या नहीं।
इस उदाहरण में, Windows-1252 चार्ट दिखाता है कि बाइट 99 "™" वर्ण को दर्शाता है। बाइट 99 ISO-8859-1 के तहत मौजूद नहीं है। अगर ™ यहां समझ में आता है, तो आप मान सकते हैं कि इनपुट Windows-1252 में था और आगे बढ़ सकते हैं। अन्यथा, आप तब तक शोध करते रह सकते हैं जब तक आपको कोई अधिक उचित वर्ण न मिल जाए।
2. तय करें कि आप स्ट्रिंग को किस एन्कोडिंग में चाहते हैं।
यह आसान है। जब तक आपके पास वास्तव में अच्छा कारण न हो, आप अपनी स्ट्रिंग्स को UTF-8 एन्कोडेड चाहते हैं।
एक अन्य सामान्य एन्कोडिंग जिसे आप Ruby में उपयोग कर सकते हैं: ASCII-8BIT। ASCII-8BIT में, प्रत्येक वर्ण को एक बाइट द्वारा दर्शाया जाता है। यानी, str.chars.length == str.bytes.length। तो, अगर आप अपनी स्ट्रिंग में विशिष्ट बाइट्स पर बहुत नियंत्रण चाहते हैं, तो ASCII-8BIT एक अच्छा विकल्प हो सकता है।
3. चरण 1 की एन्कोडिंग से चरण 2 की एन्कोडिंग में अपनी स्ट्रिंग को पुनः एन्कोड करें।
आप इसे encode विधि से कर सकते हैं। इस उदाहरण में, हमारी स्ट्रिंग थी Windows-1252 एन्कोडिंग में, और हम चाहते हैं कि यह UTF-8 बने। काफी सीधा:
irb(main):088:0> "hi\x99!".encode("UTF-8", "Windows-1252") => "hi™!"
बहुत बेहतर। (भले ही उस कॉल में एन्कोडिंग का क्रम मुझे हमेशा उल्टा लगा)।
एक ही बाइट सरणी की विभिन्न व्याख्याओं की कल्पना करना मस्तिष्क-झुकने वाला हो सकता है। खासकर जब उन व्याख्याओं में से एक टूटी हुई हो। लेकिन एन्कोडिंग के साथ अधिक सहज बनने का एक शानदार तरीका है: उनके साथ खेलें।
एक irb कंसोल खोलें, और encode, bytes, और force_encoding के साथ खिलवाड़ करें। देखें कि encode स्ट्रिंग को बनाने वाले बाइट्स को कैसे बदलता है। विभिन्न एन्कोडिंग कैसे दिखती हैं, इसके बारे में अंतर्ज्ञान बनाएं। जब आप एन्कोडिंग के साथ अधिक सहज हो जाते हैं और इन चरणों का उपयोग करते हैं, तो आप मिनटों में वह ठीक कर लेंगे जिसमें आपको पहले घंटों लगते थे।
अंत में, यदि आप इस तरह की चीजों को करने से सीखने की आदत बनाना चाहते हैं, तो मेरी किताब का मुफ्त नमूना अध्याय प्राप्त करें। कंसोल में चीजों को तोड़ना इस तरह के विचारों का अध्ययन करने का एक वास्तव में मजेदार तरीका है।