एक वाक्य में
कैरेक्टर एन्कोडिंग वह सीक्रेट डिकोडर रिंग है जिसका इस्तेमाल कंप्यूटर किसी फ़ाइल में मौजूद रॉ नंबर्स (बाइट्स) को उन अक्षरों, प्रतीकों और इमोजी में बदलने के लिए करते हैं जिन्हें आप वास्तव में पढ़ सकते हैं।
यह किस समस्या को हल करता है
शुरुआत में, ASCII था। यह सरल था, 128 कैरेक्टर्स को दर्शाने के लिए 7 बिट्स का उपयोग करता था: अंग्रेजी वर्णमाला, संख्याएं और कुछ कंट्रोल कोड्स। यह बहुत अच्छा था... अगर आप केवल अंग्रेजी बोलते। यह डिजिटल संकीर्णता एक बहुत बड़ी समस्या थी। एक कंप्यूटर é, ü, Я, या 猫 को कैसे दर्शा सकता है?
इसका जवाब एक अराजक फ्री-फॉर-ऑल था। विभिन्न क्षेत्रों और कंपनियों ने अपनी खुद की "एक्सटेंडेड ASCII" एन्कोडिंग का आविष्कार किया। ये 8-बिट सिस्टम थे जो पहले 128 स्लॉट के लिए मूल ASCII को रखते थे और बाकी 128 का उपयोग अपने विशेष कैरेक्टर्स के लिए करते थे। आपके पास पश्चिमी यूरोप के लिए ISO-8859-1 (उर्फ Latin-1), रूसी के लिए KOI8-R, जापानी के लिए Shift_JIS, और सैकड़ों अन्य थे। यह डिजिटल टॉवर ऑफ़ बेबेल था।
इसने मोजिबाके (mojibake) (文字化け, शाब्दिक रूप से "कैरेक्टर ट्रांसफॉर्मेशन") की भयानक घटना को जन्म दिया। आप किसी दूसरे देश के सहकर्मी से एक टेक्स्ट फ़ाइल खोलते और éléphant के बजाय éléphant जैसी बकवास से भरी स्क्रीन देखते। ऐसा इसलिए हुआ क्योंकि आपका कंप्यूटर फ़ाइल को अपने डिफ़ॉल्ट डिकोडर रिंग (मान लीजिए, Latin-1) का उपयोग करके पढ़ने की कोशिश कर रहा था, जबकि फ़ाइल एक अलग (जैसे UTF-8) के साथ लिखी गई थी। कंप्यूटर गलत नहीं था; उसे बस बाइट्स की व्याख्या करने के लिए गलत निर्देश दिए गए थे।
इसका बड़ा समाधान यूनिकोड (Unicode) था। सैकड़ों प्रतिस्पर्धी मैप्स होने के बजाय, यूनिकोड एक विशाल, सार्वभौमिक मैप है। यह हर कल्पना योग्य कैरेक्टर को एक यूनिक नंबर—एक "कोड पॉइंट"—असाइन करता है, A (U+0041) से लेकर ß (U+00DF) से लेकर "खुशी के आंसुओं वाला चेहरा" इमोजी 😂 (U+1F602) तक।
लेकिन यूनिकोड अपने आप में एक एन्कोडिंग नहीं है। यह सिर्फ एक मैप है। आपको अभी भी उन कोड पॉइंट्स को डिस्क पर बाइट्स के रूप में स्टोर करने का एक तरीका चाहिए। यहीं पर UTF-8 और UTF-16 जैसी एन्कोडिंग आती हैं। वे यूनिकोड स्टैंडर्ड के इम्प्लीमेंटेशन हैं। टेक्स्ट एन्कोडिंग डिटेक्शन यह पता लगाने की कला और विज्ञान है कि कोई फ़ाइल किस डिकोडर रिंग के साथ लिखी गई थी, ताकि हम अंततः मोजिबाके को समाप्त कर सकें।
यह अंदर से कैसे काम करता है
एक एन्कोडिंग का पता लगाना कोई जादू नहीं है; यह एक चतुर जासूसी का काम है। अधिकांश प्लेन टेक्स्ट फ़ाइलों में कोई फुलप्रूफ मेटाडेटा नहीं होता है जो चिल्लाकर कहे "मैं Shift_JIS के साथ एन्कोड किया गया हूँ!" इसके बजाय, टूल्स शिक्षित अनुमानों और ह्यूरिस्टिक्स की एक श्रृंखला का उपयोग करते हैं।
### बाइट्स, कैरेक्टर्स, और कोड पॉइंट्स
सबसे पहले, आइए शब्दावली को ठीक कर लें, क्योंकि यही इस पूरे साम्राज्य की कुंजी है।
- बाइट (Byte): स्टोरेज की सबसे मौलिक इकाई। 8 बिट्स का एक समूह, जो 0 से 255 तक की संख्या का प्रतिनिधित्व करता है। एक टेक्स्ट फ़ाइल, अपने मूल में, बस इन संख्याओं का एक लंबा क्रम है।
- कैरेक्टर (Character): वह चीज़ जो आप स्क्रीन पर देखते हैं। एक अक्षर, एक संख्या, एक प्रतीक, एक इमोजी।
- कोड पॉइंट (Code Point): एक यूनिक नंबर जो यूनिकोड स्टैंडर्ड एक अकेले कैरेक्टर को असाइन करता है। उदाहरण के लिए, कैरेक्टर
Aका कोड पॉइंटU+0041है।U+का अर्थ "यूनिकोड" है और संख्या हेक्साडेसिमल है। - एन्कोडिंग (Encoding): यूनिकोड कोड पॉइंट्स के एक क्रम को बाइट्स के क्रम में बदलने के नियम।
इसे ऐसे समझें: यूनिकोड दुनिया के हर व्यक्ति को एक यूनिक आईडी नंबर (कोड पॉइंट) देता है। एन्कोडिंग वह तरीका है जिससे आप उस आईडी नंबर को कागज (बाइट्स) पर लिखते हैं।
### एन्कोडिंग परिवार
विभिन्न एन्कोडिंग के अलग-अलग नियम होते हैं, और उनके यूनिक बाइट पैटर्न ही वे सुराग हैं जिनका उपयोग डिटेक्टर करते हैं।
| एन्कोडिंग | विवरण | उदाहरण: € (यूरो चिह्न, U+20AC) |
|---|---|---|
| ASCII | 7-बिट, 128 कैरेक्टर्स। सबसे पहला और असली। € को रिप्रेजेंट नहीं कर सकता। |
लागू नहीं |
| ISO-8859-15 | 8-बिट, सिंगल-बाइट। Latin-1 का एक अपडेट जिसमें यूरो चिह्न शामिल है। | A4 (एक बाइट) |
| UTF-8 | वेरिएबल-विड्थ (1-4 बाइट्स)। वेब पर इसका दबदबा है। ASCII के साथ बैकवर्ड कम्पैटिबल। | E2 82 AC (तीन बाइट्स) |
| UTF-16 (BE) | 2 या 4 बाइट्स। विंडोज और जावा में आम है। BE = बिग-एंडियन (Big-Endian)। |
20 AC (दो बाइट्स) |
| Shift_JIS | वेरिएबल-विड्थ (1 या 2 बाइट्स)। एक लेगेसी जापानी एन्कोडिंग। अपने स्टैंडर्ड रूप में € को रिप्रेजेंट नहीं कर सकता। |
लागू नहीं |
UTF-8 विशेष रूप से चतुर है। यह बाइट्स की एक परिवर्तनीय संख्या का उपयोग करता है:
- ASCII कैरेक्टर्स (0-127) केवल एक बाइट का उपयोग करते हैं, जो इसे अंग्रेजी टेक्स्ट के लिए ASCII के समान बनाता है।
- अन्य कैरेक्टर्स मल्टी-बाइट सीक्वेंस का उपयोग करते हैं। पहला बाइट आपको बताता है कि सीक्वेंस में कितने बाइट्स हैं। उदाहरण के लिए,
1110से शुरू होने वाला बाइट का मतलब है कि यह 3-बाइट कैरेक्टर की शुरुआत है। इसके बाद के बाइट्स10से शुरू होने चाहिए।
// € (U+20AC) के लिए UTF-8 सीक्वेंस
11100010 10000010 10101100
^ ^ ^
3-बाइट जारी रखने जारी रखने
सीक्वेंस वाला बाइट वाला बाइट
की शुरुआत
यह संरचना UTF-8 को "सेल्फ-सिंक्रनाइज़िंग" बनाती है। अगर आपको 10 से शुरू होने वाला कोई बाइट दिखाई देता है, तो आप जानते हैं कि आप एक कैरेक्टर के बीच में हैं, शुरुआत में नहीं। यह डिटेक्टर्स के लिए एक बहुत बड़ा सुराग है।
### डिटेक्शन एल्गोरिथ्म (यह एक अनुमान का खेल है)
तो, एक टूल किसी रहस्यमयी फ़ाइल की एन्कोडिंग का अनुमान कैसे लगाता है? यह एक चेकलिस्ट का पालन करता है, सबसे निश्चित से लेकर कम से कम निश्चित तक।
BOM (बाइट ऑर्डर मार्क) की जाँच करें: BOM एक विशेष, अदृश्य कैरेक्टर (
U+FEFF) है जिसे फ़ाइल की एन्कोडिंग घोषित करने के लिए बिल्कुल शुरुआत में रखा जाता है। यह सबसे मजबूत सुराग है जो आपको मिल सकता है।EF BB BF-> UTF-8FE FF-> UTF-16 (बिग एंडियन)FF FE-> UTF-16 (लिटिल एंडियन) यदि BOM मिल जाता है, तो जासूसी का काम आमतौर पर खत्म हो जाता है।
अमान्य बाइट सीक्वेंस की तलाश करें: यदि कोई BOM नहीं है, तो टूल फ़ाइल को सामान्य एन्कोडिंग के नियमों के खिलाफ परखता है, जिसकी शुरुआत UTF-8 से होती है। यह बाइट्स को स्कैन करता है। क्या इसे
1110से शुरू होने वाला कोई बाइट मिलता है जिसके बाद10से शुरू होने वाले दो बाइट्स नहीं हैं? यदि ऐसा है, तो फ़ाइल वैध UTF-8 नहीं है। एलिमिनेशन की यह प्रक्रिया बहुत प्रभावी है। यही तर्क UTF-16 सरोगेट पेयर्स और अन्य एन्कोडिंग नियमों पर भी लागू होता है।फ्रीक्वेंसी एनालिसिस और ह्यूरिस्टिक्स: यदि बाइट स्ट्रीम कई एन्कोडिंग के तहत मान्य है (जो हो सकता है, विशेष रूप से छोटे टेक्स्ट के साथ), तो डिटेक्टर अपनी अंतिम चाल पर जाता है: शिक्षित अनुमान। यह विभिन्न सामान्य एन्कोडिंग (
windows-1252,Shift_JIS, आदि) का उपयोग करके अस्थायी रूप से टेक्स्ट को डीकोड करेगा और परिणाम का विश्लेषण करेगा। क्याShift_JISके रूप में डीकोड करने से सामान्य जापानी कैरेक्टर्स की उच्च आवृत्ति उत्पन्न होती है? क्याISO-8859-2के रूप में डीकोड करने से प्रशंसनीय पोलिश या चेक टेक्स्ट उत्पन्न होता है? यह विभिन्न भाषाओं के सांख्यिकीय मॉडल पर निर्भर करता है। यह एकदम सही नहीं है, लेकिन यह उल्लेखनीय रूप से सटीक है।
वास्तविक दुनिया की कहानियाँ
### गड़बड़ CSV रिपोर्ट का मामला
शिकागो की एक कंपनी में एक वित्तीय विश्लेषक को उनके टोक्यो कार्यालय से त्रैमासिक बिक्री रिपोर्ट एक CSV फ़ाइल के रूप में मिलती है। वे इसे एक्सेल में खोलने के लिए डबल-क्लिक करते हैं, और घबरा जाते हैं। जापानी में सभी ग्राहक और उत्पाद नाम एक्सेंटेड कैरेक्टर्स और प्रतीकों की गड़बड़ी में हैं: 店長 (स्टोर मैनेजर) के बजाय 店長। घंटों तक, वे मानते हैं कि फ़ाइल करप्ट है।
अंत में, एक डेवलपर दोस्त एक नज़र डालता है। वे फ़ाइल को एक ऐसे टूल में खोलते हैं जो रॉ बाइट्स का निरीक्षण कर सकता है और एन्कोडिंग का पता लगा सकता है। फैसला: फ़ाइल Shift_JIS के साथ सहेजी गई थी, जो जापान में एक आम लेगेसी एन्कोडिंग है। लेकिन विश्लेषक का एक्सेल का संस्करण, जो एक अमेरिकी सिस्टम के लिए कॉन्फ़िगर किया गया था, ने मान लिया कि फ़ाइल windows-1252 (एक आम पश्चिमी एन्कोडिंग) थी। यह गलत डिकोडर रिंग लगा रहा था। एक्सेल को स्पष्ट रूप से Shift_JIS एन्कोडिंग का उपयोग करके फ़ाइल खोलने के लिए कहने पर, कैरेक्टर्स पूरी तरह से फिर से दिखाई दिए।
सबक: अंतर्राष्ट्रीय सीमाओं को पार करने वाला डेटा एन्कोडिंग समस्याओं के लिए एक माइनफील्ड है। कभी यह न मानें कि आपको प्राप्त होने वाली फ़ाइल आपके सिस्टम के समान डिफ़ॉल्ट एन्कोडिंग का उपयोग करती है।
### वह अदृश्य कैरेक्टर जिसने बिल्ड को तोड़ दिया
एक जूनियर डेवलपर एक तंग समय सीमा पर है। उन्हें एक ब्लॉग पोस्ट में एकदम सही सॉर्टिंग एल्गोरिथ्म मिलता है और वे इसे सीधे अपने पायथन स्क्रिप्ट में कॉपी-पेस्ट करते हैं। वे इसे स्थानीय रूप से चलाते हैं, और यह त्रुटिपूर्ण रूप से काम करता है। वे कोड कमिट करते हैं, और कंटीन्यूअस इंटीग्रेशन (CI) पाइपलाइन तुरंत एक रहस्यमय SyntaxError: invalid character in identifier के साथ विफल हो जाती है।
वे एक घंटे तक कोड को घूरते रहते हैं। यह उनकी मशीन पर चल रहे कोड के समान दिखता है। निराश होकर, वे एक सीनियर देव से मदद मांगते हैं। सीनियर देव अपने एडिटर में "अदृश्य कैरेक्टर्स दिखाएं" को सक्षम करता है। और वहाँ यह है: एक एकल, अदृश्य "शून्य-चौड़ाई वाला स्थान" कैरेक्टर (U+200B) दो वेरिएबल नामों के बीच छिपा हुआ है, जिसे ब्लॉग के फैंसी स्वरूपित HTML से कॉपी किया गया था। डेवलपर के आधुनिक, UTF-8-जागरूक एडिटर ने इसे अदृश्य रूप से प्रस्तुत किया, लेकिन बिल्ड सर्वर पर सख्त, पुराने लिंटर ने इसे एक अवैध कैरेक्टर के रूप में देखा और एक एरर फेंक दिया।
सबक: जो आप देखते हैं वह हमेशा वह नहीं होता जो आपको मिलता है। अदृश्य यूनिकोड कैरेक्टर्स असली होते हैं और कोडबेस में डीबग करने में मुश्किल पैदा करने वाली निराशाजनक त्रुटियों का कारण बन सकते हैं।
### टूटे हुए इमोजी का डेटाबेस
एक स्टार्टअप एक नया सोशल ऐप लॉन्च करता है। यह हिट है, लेकिन बग रिपोर्ट की बाढ़ आ जाती है। उपयोगकर्ता शिकायत करते हैं कि जब भी वे इमोजी 👍 या एक्सेंटेड कैरेक्टर जैसे naïve का उपयोग करते हैं, तो उनकी पोस्ट ? कैरेक्टर्स के साथ सहेजी जाती है। ऐप सचमुच उनकी अभिव्यक्ति को प्रश्न चिह्नों से बदल रहा है।
देव टीम स्टैक की जांच करती है। फ्रंटएंड UTF-8 JSON भेज रहा है, जो सही है। बैकएंड सर्विस इसे UTF-8 के रूप में संभाल रही है। समस्या डेटाबेस है। सेटअप के दौरान, उन्होंने अपने MySQL डेटाबेस के लिए डिफ़ॉल्ट latin1 कैरेक्टर सेट का उपयोग किया था। latin1 एक सिंगल-बाइट एन्कोडिंग है; इसमें थम्स-अप इमोजी के लिए 4-बाइट सीक्वेंस को स्टोर करने का कोई तरीका नहीं है। जब डेटाबेस को एक ऐसा कैरेक्टर मिला जिसे वह स्टोर नहीं कर सकता था, तो उसने उसे एक फॉलबैक ? से बदल दिया। इस समस्या को ठीक करने के लिए utf8mb4 कैरेक्टर सेट में एक दर्दनाक डेटाबेस माइग्रेशन शामिल था, जो पूर्ण यूनिकोड समर्थन प्रदान करता है।
सबक: आपकी पूरी डेटा पाइपलाइन, उपयोगकर्ता के ब्राउज़र से लेकर डेटाबेस डिस्क तक, एक ही एन्कोडिंग में बात करनी चाहिए। एक भी कमजोर कड़ी आपके डेटा को करप्ट कर देगी।
आम गलतियाँ और जाल
- यह मान लेना कि सब कुछ UTF-8 है। जबकि यह वेब की लिंग्वा फ्रांका (lingua franca) है, यह सार्वभौमिक नहीं है। नेटिव ऐप्स, लेगेसी सिस्टम, और एक्सेल जैसे टूल से डेटा एक्सपोर्ट अक्सर पुरानी, क्षेत्रीय एन्कोडिंग का उपयोग करते हैं। हमेशा सत्यापित करें, कभी भी मानें नहीं।
- यूनिकोड और UTF-8 के बीच भ्रमित होना। वे एक ही चीज़ नहीं हैं। यूनिकोड एक एब्स्ट्रैक्ट स्टैंडर्ड है (कैरेक्टर मैप)। UTF-8 एक ठोस एन्कोडिंग है (स्टोरेज फॉर्मेट)। यह कहना कि "यह फ़ाइल यूनिकोड है" imprecise है; आपका मतलब है कि यह शायद UTF-8, UTF-16, या UTF-32 है।
- BOM के बारे में भूल जाना। जब आप एक UTF-8 फ़ाइल पढ़ते हैं जिसमें BOM होता है, तो आपको उन पहले तीन बाइट्स (
Latin-1 में) को हटा देना चाहिए। यदि आप ऐसा नहीं करते हैं, तो वे आपकी सामग्री की शुरुआत में कचरे के रूप में दिखाई दे सकते हैं, JSON/XML पार्सर्स को तोड़ सकते हैं, या HTTP हेडर को विफल कर सकते हैं। - MySQL/MariaDB में
utf8mb4के बजायutf8का उपयोग करना। यह एक क्लासिक डेटाबेस जाल है। MySQL मेंutf8कैरेक्टर सेट एक टूटा हुआ, पुराना इम्प्लीमेंटेशन है जो प्रति कैरेक्टर केवल 3 बाइट्स तक का समर्थन करता है। इसका मतलब है कि यह कई इमोजी और कुछ अन्य प्रतीकों को स्टोर नहीं कर सकता है। आप लगभग हमेशाutf8mb4का उपयोग करना चाहेंगे। - डबल-एन्कोडिंग। यह एक विशेष रूप से गंदी समस्या है जहाँ आप ऐसा टेक्स्ट लेते हैं जो पहले से ही UTF-8 है, लेकिन आप गलती से किसी प्रोग्राम को बताते हैं कि यह Latin-1 है। प्रोग्राम फिर उस "Latin-1" डेटा को लेता है और सहायक रूप से इसे UTF-8 में बदल देता है। परिणाम
éके लिएéजैसा कचरा होता है, जो एक कैरेक्टर के UTF-8 रिप्रेजेंटेशन का UTF-8 रिप्रेजेंटेशन है। इसे उलटना अक्सर बहुत मुश्किल होता है।
यह आपके रडार पर क्यों होना चाहिए
यदि आप ऐसा कोड लिखते हैं जो किसी टेक्स्ट फ़ाइल, एक API, एक डेटाबेस, या उपयोगकर्ता इनपुट को छूता है, तो आप कैरेक्टर एन्कोडिंग से निपट रहे हैं। यह कोई गूढ़, "जान लें तो अच्छा है" वाला विषय नहीं है; यह डेटा अखंडता का एक मौलिक हिस्सा है।
आपको एन्कोडिंग के बारे में सोचना चाहिए जब भी आप:
- डिस्क पर फ़ाइलें पढ़ते या लिखते हैं (
.csv,.txt,.json,.xml, आदि)। - HTTP रिक्वेस्ट से डेटा प्राप्त करते हैं या HTTP रिस्पांस भेजते हैं।
- एक डेटाबेस से कनेक्ट और क्वेरी करते हैं।
- दुनिया भर के उपयोगकर्ताओं द्वारा सबमिट किए गए टेक्स्ट को प्रोसेस करते हैं।
- लेगेसी सिस्टम या तीसरे पक्ष के डेटा के साथ काम करते हैं।
एन्कोडिंग को गलत समझना सूक्ष्म डेटा करप्शन, निराशाजनक बग और दुखी उपयोगकर्ताओं की ओर ले जाता है। इसे समझना एक पेशेवर डेवलपर की निशानी है जो मजबूत, वैश्विक-तैयार सॉफ़्टवेयर बनाने की परवाह करता है।
और गहराई में जाएं
- The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!) - जोएल स्पोल्स्की का वह महान, अवश्य पढ़ा जाने वाला निबंध जिसने डेवलपर्स की पीढ़ियों को ज्ञान दिया है।
- W3C: Character encodings - W3C का अवलोकन कि वेब के लिए एन्कोडिंग कैसे काम करती है, जिसमें HTTP हेडर और HTML मेटा टैग शामिल हैं।
- The Unicode Standard - यूनिकोड कंसोर्टियम की आधिकारिक वेबसाइट। यूनिकोड से संबंधित सभी चीजों के लिए सत्य का स्रोत।
- UTF-8 (RFC 3629) - तकनीकी विनिर्देश जो UTF-8 को परिभाषित करता है। यह घना है लेकिन निश्चित है।
- Wikipedia: Mojibake - गड़बड़ टेक्स्ट के इतिहास और तकनीकी कारणों पर एक बेहतरीन लेख।