1. حرف کا نمبر اور محفوظ ہونے والے بائٹس الگ ہیں
فرض کریں آپ نے کوریائی دستاویز برآمد کرکے دوبارہ کھولی تو عنوان عجیب حروف میں نظر آیا۔ لکھنے والے کی زبان نہیں بدلی؛ ممکن ہے محفوظ اعداد پڑھنے کے اصول مختلف ہوگئے ہوں۔ Unicode ایک معیار ہے جو حروف اور علامات کو کوڈ پوائنٹ کہلانے والے نمبر دیتا ہے، جبکہ UTF-8 ان متعلقہ قدروں کو بائٹس کی ترتیب میں ظاہر کرنے والی انکوڈنگ ہے۔ مثلاً کوریائی ہجے ‘가’ کا کوڈ پوائنٹ U+AC00 ہے۔ U+ کے بعد عدد سولہ اساس میں لکھا ہے؛ یہ فائل میں ترتیب یا میموری کا پتہ نہیں بتاتا۔ یہ نمبر فونٹ کی شکل یا سکرین کے پکسل کی جگہ بھی مقرر نہیں کرتا۔ ایک ہی کوڈ پوائنٹ مختلف فونٹس اور حروف چینی کے ماحول میں مختلف دکھ سکتا ہے۔ اس لیے Unicode کی سہولت، UTF-8 میں محفوظ کرنا اور کوریائی فونٹ نصب کرنا متعلق ضرور ہیں مگر الگ جانچنے چاہییں۔ Unicode کی UTF وضاحت حرف اور محفوظ کرنے کی صورت الگ سمجھنے کی ابتدا ہے۔
UTF-8 میں ‘가’ سولہ اساس کے تین بائٹس EA B0 80 بنتا ہے۔ اس کے مقابلے میں لاطینی A کا کوڈ U+0041 ہے اور UTF-8 میں ایک بائٹ 41 ہے۔ بائٹ آٹھ بِٹس کی اکائی ہے؛ ایک دستاویز میں بھی ہر حرف کی بائٹ لمبائی مختلف ہوسکتی ہے۔ صرف .txt یا .csv توسیع سے اصل انکوڈنگ معلوم نہیں ہوتی۔ UTF-8 درست Unicode سکیلر قدروں کو ایک سے چار بائٹس میں ظاہر کرتا ہے، اس لیے دکھائی دینے والے حروف کو کسی مستقل عدد سے ضرب دے کر فائل کا درست حجم نہیں نکال سکتے۔ اس کوریائی ہجے کی مثال تمام کوریائی علامات یا ہر زبان پر بھی لاگو نہیں کی جاسکتی۔ انکوڈنگ حروف کی معلومات بائٹس میں منتقل کرنے کا قاعدہ ہے، کمپریشن یا خفیہ کاری نہیں۔ ایک ہی جملے کا مجموعی حجم فائل فارمیٹ کی اضافی معلومات، نئی سطروں اور منتقلی کے دوران کمپریشن سے بدل سکتا ہے۔ WHATWG Encoding Standard کی بائٹس اور حروف کے درمیان تبدیلی کو پوری فائل کے حجم اور رازداری کے کام سے الگ رکھنا مسئلے کا دائرہ محدود کرتا ہے۔
2. بائٹس، کوڈ یونٹس اور نظر آنے والے حروف کی گنتی
JavaScript میں سٹرنگ کی length پڑھنے سے UTF-16 کوڈ یونٹس کی تعداد ملتی ہے۔ یہ UTF-8 فائل کے بائٹس یا انسان کو محسوس ہونے والے حروف کی تعداد نہیں۔ مثلاً مسکراتا چہرہ ‘😀’ ایک U+1F600 کوڈ پوائنٹ ہے، مگر دو UTF-16 یونٹس لیتا ہے، اس لیے '😀'.length کی قدر 2 ہے۔ UTF-8 میں یہ F0 9F 98 80 یعنی چار بائٹس ہے۔ codePointAt(0) سے ملنے والا عشری عدد 128512 وہی نمبر ہے جو U+1F600، نہ کہ حروف کی گنتی یا فائل کا حجم۔ ‘가’ کے لیے ایک کوڈ پوائنٹ، ایک UTF-16 یونٹ اور تین UTF-8 بائٹس ہیں۔ ایک ہی سٹرنگ کے مختلف نتائج کی وجہ پیمائش کی الگ اکائیاں ہیں۔ MDN کی سٹرنگ کی لمبائی کی وضاحت length کی اکائی واضح کرتی ہے۔ اس سے یہ بھی قطعی نہیں بتایا جاسکتا کہ JavaScript انجن حقیقت میں کتنے بائٹس میموری استعمال کرتا ہے۔
کوڈ پوائنٹس الگ الگ گننے سے بھی ہمیشہ صارف کو نظر آنے والے حروف کی تعداد نہیں ملتی۔ بنیادی حرف کے ساتھ ملنے والی علامت لگ سکتی ہے، یا کئی کوڈ پوائنٹس ایک ایموجی بنا سکتے ہیں۔ Unicode کے متن کی تقسیم کے قواعد توسیع شدہ گرافیم کلسٹرز کی حدیں سمجھاتے ہیں۔ Array.from(text) کی طرح کوڈ پوائنٹس کے حساب سے سٹرنگ کھولنے کا طریقہ کئی پوائنٹس کے مجموعوں کو خود بخود نہیں گنتا۔ براؤزر میں ماحول کی سہولت جانچ کر Intl.Segmenter کی granularity کو 'grapheme' مقرر کرنے پر غور کیا جاسکتا ہے۔ البتہ کلسٹر لازماً فونٹ کی ایک تصویری شکل کے برابر نہیں ہوتا، اور تدوین کی توقعات زبان کے لحاظ سے بدل سکتی ہیں۔ تعارفی خانے میں صارف کو سمجھ آنے والی حرف گنتی رکھیں، جبکہ ذخیرے اور رابطے کی بائٹ حد الگ ہو۔ سکرین پر ‘20 حروف’ لکھ کر اندر صرف UTF-16 یونٹس کاٹنا ایموجی یا مرکب حرف کو درمیان سے توڑ سکتا ہے۔
3. کوریائی متن بگڑے تو ذخیرہ، ترسیل اور نمائش الگ دیکھیں
بائٹس لکھنے کی انکوڈنگ اور پڑھنے کی ڈی کوڈنگ مختلف ہو تو متن بگڑ سکتا ہے۔ UTF-8 فائل کو دوسری انکوڈنگ سمجھ کر پڑھنے سے خود فائل بدلے بغیر بھی غلط حروف دکھ سکتے ہیں۔ HTML میں اصل ذخیرہ فارمیٹ، HTTP کے Content-Type میں charset اور دستاویز کے شروع کا meta charset ایک ساتھ دیکھیں۔ HTML کا lang='ko' مواد کی زبان بتاتا ہے؛ یہ کوریائی بائٹس پڑھنے کی انکوڈنگ منتخب کرنے والے charset سے الگ کردار ہے۔ W3C کی انکوڈنگ اعلان کی رہنمائی کہتی ہے کہ صرف اعلان UTF-8 نہ بنائیں، فائل واقعی UTF-8 میں محفوظ کریں اور سرور و دستاویز کے اعلانات ملائیں۔ انکوڈنگ کی شناختی علامت فیصلے کی ترجیح پر بھی اثر ڈال سکتی ہے؛ meta کو ہر دوسری معلومات پر لازماً غالب نہ سمجھیں۔ فائل براہ راست کھولنے اور سرور سے لینے کے نتائج مختلف ہوں تو ترسیل کی ترتیبات اہم سراغ ہیں۔
فونٹ میں مطلوبہ نقش نہ ہونے کی وجہ سے چوکور خانے دکھنا غلط ڈی کوڈنگ سے مختلف مسئلہ ہوسکتا ہے۔ اگر حرف کی معلومات درست ہیں مگر بنانے کی شکل نہیں مل رہی، تو ذخیرے کی انکوڈنگ بدلنے سے مسئلہ حل نہیں ہوگا۔ اس کے برعکس پہلے ہی غلط حروف میں پڑھے گئے متن کو نئے فونٹ سے دکھانا اصل حروف واپس نہیں لاتا۔ متاثرہ فائل کی نقل محفوظ کرکے مدیر کی منتخب انکوڈنگ، سرور کا اعلان، براؤزر کے پڑھے حروف اور فونٹ ترتیب سے موازنہ کریں۔ صرف شکل دیکھ کر سبب طے نہ کریں؛ اسی حصے کو نقل کرنے پر حاصل کوڈ پوائنٹس بھی دیکھیں۔ یہ لکھیں کہ فرق صرف کسی ایک براؤزر میں ہے یا دوسرے مدیر بھی فائل غلط پڑھتے ہیں؛ یوں نمائش اور معلومات کی تبدیلی الگ ہوگی۔ درست حروف نظر آنے تک بار بار محفوظ کرنا اصل بائٹس کھو سکتا ہے۔ تمام اعلانات صحیح ہونے پر بھی کوئی مخصوص تحریر خراب ہو تو دیکھیں وہ ڈیٹابیس میں داخل ہونے سے پہلے کس مرحلے پر بدلی۔
4. TextEncoder اور TextDecoder سے وہی قدریں جانچیں
سادہ تجربہ اپنی بنائی ہوئی مختصر سٹرنگ سے شروع کریں۔ TextEncoder JavaScript سٹرنگ کو UTF-8 بائٹ صف میں بدلتا ہے۔ new TextEncoder().encode('가') کا سولہ اساس نتیجہ EA B0 80 ہے اور صف کی length برابر 3 ہے۔ ترقیاتی اوزار وہی قدریں عشری 234، 176، 128 دکھا سکتے ہیں؛ یہ دوسرا ڈیٹا نہیں، اعداد لکھنے کی اساس کا فرق ہے۔ اسی سٹرنگ کی عام length، جو 1 ہے، سے موازنہ اکائیوں کا فرق واضح کرتا ہے۔ صف کو new TextDecoder('utf-8').decode(bytes) سے پڑھیں تو ‘가’ ملتا ہے؛ یہاں bytes پہلے بنائی ہوئی بائٹ صف ہے۔ انکوڈر UTF-8 بناتا ہے، کسی بھی منتخب پرانی انکوڈنگ میں محفوظ کرنے والا عمومی مبدل نہیں۔ اصل فائل جانچتے وقت پہلے حاصل کردہ اصل بائٹس لیں۔ پہلے ہی غلط پڑھے گئے سکرین کے جملے کو دوبارہ UTF-8 میں انکوڈ کرنا ابتدائی فائل کے بائٹس ثابت نہیں کرتا۔
TextDecoder کے constructor میں 'utf-8' اور { fatal: true } مقرر کرنے سے ناموافق مدخل پر خاموش تبدیلی کے بجائے خرابی ہوسکتی ہے۔ مثلاً اکیلا FF بائٹ درست UTF-8 نہیں، اس لیے اس حالت میں ڈی کوڈنگ ناکام ہوتی ہے۔ طے شدہ متبادل حالت میں خراب حصے کی جگہ U+FFFD متبادل حرف آسکتا ہے۔ لیکن خرابی نہ آنا یہ نہیں کہ اصل انکوڈنگ معلوم ہوگئی یا متن کی درستی تصدیق ہوگئی۔ بعض بائٹس مختلف انکوڈنگز میں مشترک ہیں، اور غلط پڑھے ہوئے حروف پہلے ہی دوبارہ درست UTF-8 میں محفوظ ہوئے ہوسکتے ہیں۔ یہ جانچ صرف منتخب ڈی کوڈر کا مدخل قبول کرنا دیکھتی ہے۔ دستاویز کا ماخذ، اصل سے مطابقت اور درمیان میں فائل کے نہ بدلے جانے کی خودکار تصدیق نہیں کرتی۔
5. نارملائزیشن متبادل نمائندگیوں کی الگ ترتیب ہے
درست پڑھی ہوئی دو سٹرنگز کے اندر بھی کوڈ پوائنٹس کی ترتیب مختلف ہوسکتی ہے۔ ‘가’ کو ایک U+AC00 سے یا باہم ملنے والے ابتدائی صامت U+1100 اور درمیانی مصوتے U+1161 کی ترتیب سے ظاہر کیا جاسکتا ہے۔ یہ دونوں قدریں عام مطابقتی جامو ‘ㄱ’ اور ‘ㅏ’ کو ساتھ لکھنے سے مختلف ہیں، اس لیے نمبر بھی جانچیں۔ دونوں عموماً ایک ہجے کی صورت بنتے ہیں مگر JavaScript کی خام سٹرنگ موازنے میں مختلف ہوسکتے ہیں۔ Unicode کے نارملائزیشن قواعد کے مطابق دونوں پر NFC لگانا اس canonical طور پر مساوی مثال کو ایک ہی نمائندگی میں لاتا ہے۔ NFD، canonical تحلیل کرتا ہے۔ اس مثال میں NFC کی UTF-8 شکل تین بائٹس اور NFD کے دو جامو چھ بائٹس ہیں؛ شکل ایک ہو تو بھی ذخیرے کا حجم مختلف ہوسکتا ہے۔ تلاش کا لفظ اور محفوظ نام نظر میں ایک جیسے ہوں مگر نہ ملیں تو یہ فرق جانچیں؛ اسے بائٹس کی غلط تشریح سے پیدا ہونے والی خرابی سے الگ رکھیں۔
نارملائزیشن کی صورت بھی مقصد کے لحاظ سے چنیں۔ NFC canonical مساوات سے متعلق ہے، جبکہ NFKC میں compatibility تحلیل بھی شامل ہے، جو پوری چوڑائی یا دائرے میں لکھے ہندسوں جیسے الگ داخل کردہ فرق زیادہ وسیع انداز میں بدل سکتی ہے۔ تلاش کی موازنہ نقل بنانے میں یہ مددگار ہوسکتا ہے، لیکن ریاضی کی علامت یا اصل دستاویز میں فرق معنی رکھ سکتا ہے۔ اس لیے اصل محفوظ رکھ کر ضروری موازنہ نقل کے لیے صورت مقرر کرنا مفید ہے۔ نارملائزیشن بڑے چھوٹے لاطینی حروف کے موازنے، زبان کے حساب سے ترتیب یا ایک آواز والے الفاظ کی تلاش کا بدل بھی نہیں۔ پرانے فائل نام یا اکاؤنٹ شناختیں اجتماعی طور پر بدلیں تو مختلف چیزیں ایک موازنہ قدر میں ضم ہوسکتی ہیں؛ پہلے نام گذاری اور تصادم کے قواعد دیکھیں۔ ہر ملتی جلتی دکھائی دینے والی علامت کو ایک قدر بنا کر محفوظ کرنا نارملائزیشن کا عمومی مقصد نہیں۔
6. اصل متن محفوظ رکھیں اور تبدیلی کی سرحدیں لکھیں
خرابی کا سبب محدود کرتے وقت پہلی فائل پر لکھنے سے پہلے اصل بائٹس اور حصول کا راستہ محفوظ کریں۔ نقل کو متوقع انکوڈنگ میں پڑھیں، پھر درست نظر آنے والے نتیجے کو دوبارہ محفوظ کرکے دیکھیں کہ وہی مواد برقرار ہے۔ W3C کی BOM وضاحت کے مطابق UTF-8 کی ابتدائی علامت EF BB BF ہے، اور یہ بائٹس لازمی نہیں۔ UTF-8 میں بائٹس کی ترتیب منتخب نہیں کرنی پڑتی، اس لیے اس علامت کو UTF-16 میں ترتیب چننے کا وہی کام نہ سمجھیں۔ BOM لگانا یا ہٹانا اور متن کے بائٹس دوسری انکوڈنگ میں بدلنا بھی الگ ہیں۔ اگر ناقابلِ مطالعہ قدریں متبادل حرف یا سوالیہ نشان بن کر محفوظ ہوگئی ہوں، تو کئی اصل قدریں ایک میں مل گئی ہوسکتی ہیں؛ خودکار بحالی یقینی نہیں۔ اصل انکوڈنگ اور تبدیلی کی تاریخ معلوم ہونے پر ہی واپسی کا امکان جانچیں؛ نارملائزیشن گم شدہ بائٹس بحال کرنے کا اوزار نہیں۔
کثیر لسانی سہولت کی جانچ صرف ایک انگریزی سطر پر ختم نہ کریں۔ مختصر نمونوں میں کوریائی ہجا، ملاپ کی علامت والا لاطینی حرف، اضافی سطح کا ایموجی، اور عربی یا عبرانی جیسا دائیں سے بائیں متن شامل کرکے داخلہ، ذخیرہ، دوبارہ پڑھنا اور برآمد موازنہ کریں۔ ہر مرحلے پر شکل، کوڈ پوائنٹس، UTF-8 بائٹ تعداد اور مصنوعات کی مقرر کردہ حرف گنتی جانچیں۔ پڑھنے کی سمت UTF-8 کو کسی دوسری انکوڈنگ میں بدلنے سے درست نہیں ہوتی؛ سکرین کی زبان اور سمت الگ دیکھیں۔ داخلے کی حد یا تلاش کا موازنہ بدلتے وقت بھی اصل متن محفوظ کریں اور نیا معیار بتائیں۔ براؤزر کا دکھایا عدد اور سرور کی قبولیت کی حد ایک اکائی استعمال کرتے ہیں یا نہیں، دیکھیں؛ مختلف حدیں درکار ہوں تو ہر ایک دکھائیں۔ اس مضمون کے اعداد اور کوڈ مختصر مثالی سٹرنگز کی تبدیلی ہیں، کسی مخصوص خدمت کی خرابی کی پیمائش نہیں۔ حرف کے نمبر، محفوظ بائٹس، سٹرنگ کی اکائی، نمائش اور موازنے کے قواعد ترتیب سے دیکھنا ہر سرحد پر تبدیلی کو دوبارہ پیدا کرنے دیتا ہے۔