आप वास्तव में केवल एक स्ट्रिंग के एन्कोडिंग के बारे में सोचते हैं जब वह टूट जाता है। जब आप अपने अपवाद ट्रैकर की जांच करें और देखें
Encoding::InvalidByteSequenceError: "\xFE" on UTF-8
आपको चेहरे पर घूर रहा है। या हो सकता है कि "वे हैं" "वे फिर से" के रूप में दिखाई देने लगें।
तो, जब आपके पास एक खराब एन्कोडिंग है, तो आप कैसे पता लगाते हैं कि क्या टूट गया? और आप इसे कैसे ठीक कर सकते हैं?
एन्कोडिंग क्या है?
यदि आप कल्पना कर सकते हैं कि एक स्ट्रिंग में एन्कोडिंग क्या करती है, तो इन बगों को ठीक करना आसान होता है।
आप स्ट्रिंग को बाइट्स की एक सरणी, या छोटी संख्या के रूप में सोच सकते हैं:
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, इसमें वह अजीब बैकस्लैश नंबर नहीं होगा। तो आप अपनी स्ट्रिंग के लिए सही एन्कोडिंग का पता कैसे लगाते हैं?
बहुत सारे पुराने सॉफ़्टवेयर एकल डिफ़ॉल्ट एन्कोडिंग से चिपके रहेंगे, ताकि आप शोध कर सकें कि इनपुट कहाँ से आया है। क्या किसी ने इसे Word से चिपकाया है? यह विंडोज-1252 हो सकता है। क्या यह किसी फ़ाइल से आया है या आपने इसे किसी पुरानी वेबसाइट से निकाला है? यह ISO-8859-1 हो सकता है।
मुझे एन्कोडिंग तालिकाओं की खोज करने में भी मदद मिली है, जैसे कि उन लिंक किए गए विकिपीडिया पृष्ठों पर। उन तालिकाओं पर, आप अज्ञात संख्याओं द्वारा संदर्भित वर्णों को देख सकते हैं, और देख सकते हैं कि क्या वे संदर्भ में अर्थपूर्ण हैं।
इस उदाहरण में, Windows-1252 चार्ट दिखाता है कि बाइट 99
"™" वर्ण का प्रतिनिधित्व करता है। बाइट 99
ISO-8859-1 के तहत मौजूद नहीं है। अगर ™ यहां समझ में आता है, तो आप मान सकते हैं कि इनपुट विंडोज-1252 में था और आगे बढ़ें। अन्यथा, आप तब तक शोध करते रह सकते हैं जब तक आपको कोई ऐसा पात्र नहीं मिल जाता जो अधिक उचित लगता है।
2. तय करें कि आप कौन सी एन्कोडिंग चाहते हैं स्ट्रिंग होना चाहिए।
यह आसान है। जब तक आपके पास वास्तव में कोई अच्छा कारण न हो, आप चाहते हैं कि आपके तार UTF-8 एन्कोडेड हों।
रूबी में आप एक अन्य सामान्य एन्कोडिंग का उपयोग कर सकते हैं:ASCII-8BIT। ASCII-8BIT में, प्रत्येक वर्ण को एक बाइट द्वारा दर्शाया जाता है। यानी str.chars.length == str.bytes.length
. इसलिए, यदि आप अपनी स्ट्रिंग में विशिष्ट बाइट्स पर बहुत अधिक नियंत्रण चाहते हैं, तो ASCII-8BIT एक अच्छा विकल्प हो सकता है।
3. चरण 1 में एन्कोडिंग से चरण 2 में एन्कोडिंग में अपनी स्ट्रिंग को फिर से एन्कोड करें।
आप इसे encode
. के साथ कर सकते हैं तरीका। इस उदाहरण में, हमारा स्ट्रिंग था Windows-1252 एन्कोडिंग में, और हम चाहते हैं यह यूटीएफ -8 बनने के लिए। बहुत सीधा:
irb(main):088:0> "hi\x99!".encode("UTF-8", "Windows-1252")
=> "hi™!"
काफी बेहतर। (भले ही उस कॉल में एन्कोडिंग का क्रम मुझे हमेशा पीछे की ओर लगता था)।
बाइट्स की एक ही सरणी की विभिन्न व्याख्याओं की कल्पना करना दिमाग को झुकाने वाला हो सकता है। विशेष रूप से जब उन व्याख्याओं में से एक को तोड़ा जाता है। लेकिन एन्कोडिंग के साथ अधिक सहज बनने का एक शानदार तरीका है:उनके साथ खेलें।
एक irb
खोलें कंसोल, और encode
के साथ गड़बड़ करें , bytes
, और force_encoding
. देखें कि कैसे encode
स्ट्रिंग बनाने वाले बाइट्स को बदलता है। विभिन्न एनकोडिंग कैसी दिखती हैं, इसके बारे में अंतर्ज्ञान बनाएं। जब आप एन्कोडिंग के साथ अधिक सहज हो जाते हैं और इन चरणों का उपयोग करते हैं, तो आप मिनटों में ठीक कर देंगे जो आपको घंटों पहले लगे होंगे।
आखिरकार, अगर आप सीखना चाहते हैं कि इस तरह की चीजों को सीखने की आदत कैसे बनाई जाए, तो मेरी किताब का मुफ्त नमूना अध्याय लें। कंसोल में चीजों को तोड़ना एक वास्तव में है इस तरह के विचारों का अध्ययन करने का मजेदार तरीका।