आप वास्तव में एक स्ट्रिंग के एनकोडिंग के बारे में तभी सोचते हैं जब यह टूट जाता है। जब आप अपने एक्सेप्शन ट्रैकर की जांच करते हैं और देखते हैं
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] द्वारा दर्शाया गया है। लेकिन बाइट्स और कैरेक्टर के बीच अभी भी एक संबंध है। और एक स्ट्रिंग का एनकोडिंग उस संबंध को परिभाषित करता है।
एक ही बाइट सेट को देखें जब आप अलग-अलग एनकोडिंग आजमाते हैं:
# Try an ISO-8859-1 string with a special character! 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] # What would that string look like interpreted as ISO-8859-5 instead? 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>'
अधिकांश एनकोडिंग छोटे होते हैं, और हर संभावित कैरेक्टर को हैंडल नहीं कर सकते। आप उस एरर को तब देखेंगे जब एक एनकोडिंग में एक कैरेक्टर दूसरे में मौजूद न हो, या जब रूबी दो एनकोडिंग के बीच एक कैरेक्टर का अनुवाद करने का तरीका न समझ पाए।
यदि आप 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 होता, तो उसमें वह अजीब बैकस्लैश नंबर नहीं होता। तो आप अपने स्ट्रिंग के लिए सही एनकोडिंग कैसे पता लगाते हैं?
बहुत सारा पुराना सॉफ्टवेयर एक डिफ़ॉल्ट एनकोडिंग पर टिका रहता है, इसलिए आप शोध कर सकते हैं कि इनपुट कहां से आया। क्या किसी ने वर्ड से पेस्ट किया? यह Windows-1252 हो सकता है। क्या यह किसी फाइल से आया या आपने इसे किसी पुरानी वेबसाइट से खींचा? यह ISO-8859-1 हो सकता है।
मुझे उन लिंक किए गए विकिपीडिया पेजों पर एनकोडिंग टेबल खोजना भी मददगार लगा है। उन टेबल पर, आप अज्ञात संख्याओं द्वारा संदर्भित कैरेक्टर को देख सकते हैं, और देख सकते हैं कि वे संदर्भ में समझ में आते हैं या नहीं।
इस उदाहरण में, Windows-1252 चार्ट दिखाता है कि बाइट 99 "™" कैरेक्टर को दर्शाता है। बाइट 99 ISO-8859-1 के तहत मौजूद नहीं है। अगर ™ यहां समझ में आता है, तो आप मान सकते हैं कि इनपुट Windows-1252 में था और आगे बढ़ सकते हैं। अन्यथा, आप तब तक शोध जारी रख सकते हैं जब तक आपको एक अधिक उचित कैरेक्टर न मिल जाए।
2. तय करें कि आप चाहते हैं कि स्ट्रिंग किस एनकोडिंग में हो।
यह आसान है। जब तक आपके पास वास्तव में अच्छा कारण न हो, आप चाहते हैं कि आपके स्ट्रिंग्स UTF-8 एनकोडेड हों।
रूबी में एक और आम एनकोडिंग है जिसका आप उपयोग कर सकते हैं: 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 स्ट्रिंग को बनाने वाले बाइट्स को कैसे बदलता है। विभिन्न एनकोडिंग कैसे दिखते हैं, इसके बारे में अंतर्ज्ञान बनाएं। जब आप एनकोडिंग के साथ अधिक सहज हो जाते हैं और इन चरणों का उपयोग करते हैं, तो आप मिनटों में उसे ठीक कर लेंगे जिसमें पहले आपको घंटों लगते थे।
अंत में, यदि आप इस तरह की चीजों को करने से सीखने की आदत बनाना चाहते हैं, तो मेरी किताब का मुफ्त नमूना अध्याय प्राप्त करें। कंसोल में चीजों को तोड़ना इस तरह के विचारों का अध्ययन करने का एक वास्तव में मजेदार तरीका है।