FlowingDev

شرح ترميز النصوص: من فن ASCII إلى كوابيس الـ Mojibake

افهم ترميز النصوص، النظام الذي يحول البايتات إلى محارف مقروءة، واعرف لماذا تظهر الملفات أحيانًا على شكل خرابيش غير مفهومة (mojibake).

جرّب الأداة: Text Encoding Detector

في جملة واحدة

ترميز المحارف (Character encoding) هو حلقة فك الشفرة السرية التي تستخدمها الحواسيب لتحويل الأرقام الخام (البايتات) في ملف ما إلى الحروف والرموز والإيموجيز التي يمكنك قراءتها فعليًا.

المشكلة التي يحلها

في البداية، كان هناك ASCII. كان بسيطًا، يستخدم 7 بت لتمثيل 128 محرفًا: الأبجدية الإنجليزية، الأرقام، وبعض أكواد التحكم. كان رائعًا... إذا كنت تتحدث الإنجليزية فقط. هذه الإقليمية الرقمية كانت مشكلة ضخمة. كيف يمكن للكمبيوتر أن يمثل é، ü، Я، أو 猫؟

كان الجواب فوضى عارمة. اخترعت مناطق وشركات مختلفة ترميزاتها الخاصة المسماة "ASCII الموسع". كانت هذه أنظمة 8 بت التي حافظت على ASCII الأصلي في أول 128 خانة واستخدمت الـ 128 الأخرى لمحارفها الخاصة. كان لديك ISO-8859-1 (المعروف أيضًا بـ Latin-1) لأوروبا الغربية، KOI8-R للغة الروسية، Shift_JIS لليابانية، ومئات غيرها. لقد كان برج بابل الرقمي.

هذا خلق الظاهرة المرعبة المعروفة باسم mojibake (文字化け، حرفيًا "تحول المحارف"). كنت تفتح ملفًا نصيًا من زميل في بلد آخر وترى شاشة مليئة بالطلاسم مثل éléphant بدلًا من éléphant. حدث هذا لأن جهاز الكمبيوتر الخاص بك كان يحاول قراءة الملف باستخدام حلقة فك الشفرة الافتراضية لديه (لنقل Latin-1) بينما تمت كتابة الملف بحلقة مختلفة (مثل UTF-8). الكمبيوتر لم يكن مخطئًا؛ لقد أُعطي التعليمات الخاطئة لتفسير البايتات.

الحل الكبير كان Unicode. بدلًا من وجود مئات الخرائط المتنافسة، يونيكود هو خريطة واحدة عملاقة وعالمية. إنه يخصص رقمًا فريدًا — "نقطة رمزية" أو "code point" — لكل محرف يمكن تخيله، من A (U+0041) إلى ß (U+00DF) إلى إيموجي "وجه بدموع الفرح" 😂 (U+1F602).

لكن يونيكود بحد ذاته ليس ترميزًا. إنه مجرد الخريطة. ما زلت بحاجة إلى طريقة لتخزين هذه النقاط الرمزية كبايتات على القرص. هنا يأتي دور ترميزات مثل UTF-8 و UTF-16. إنها تطبيقات معيار يونيكود. اكتشاف ترميز النص هو فن وعلم معرفة أي حلقة فك شفرة استُخدمت لكتابة الملف، حتى نتمكن أخيرًا من وضع حد للـ mojibake.

كيف يعمل من الداخل

اكتشاف الترميز ليس سحرًا؛ إنه عمل تحرّي ذكي. لا توجد بيانات وصفية (metadata) مضمونة في معظم الملفات النصية العادية تصرخ "أنا مرمّز بـ Shift_JIS!". بدلًا من ذلك، تستخدم الأدوات سلسلة من التخمينات المدروسة والاستدلالات.

### البايتات، المحارف، والنقاط الرمزية (Code Points)

أولاً، دعنا نوضح المصطلحات، لأنها مفتاح المملكة.

  • بايت (Byte): وحدة التخزين الأساسية. مجموعة من 8 بت، تمثل رقمًا من 0 إلى 255. الملف النصي، في جوهره، هو مجرد سلسلة طويلة من هذه الأرقام.
  • محرف (Character): الشيء الذي تراه على الشاشة. حرف، رقم، رمز، إيموجي.
  • نقطة رمزية (Code Point): رقم فريد يخصصه معيار يونيكود لمحرف واحد. على سبيل المثال، المحرف A له النقطة الرمزية U+0041. U+ تعني "Unicode" والرقم مكتوب بالنظام الست عشري (hexadecimal).
  • ترميز (Encoding): القواعد لتحويل سلسلة من نقاط يونيكود الرمزية إلى سلسلة من البايتات.

فكر في الأمر هكذا: يونيكود يعطي كل شخص في العالم رقم هوية فريد (code point). الترميز هو الطريقة التي تستخدمها لكتابة رقم الهوية هذا على الورق (بايتات).

### عائلات الترميز

الترميزات المختلفة لها قواعد مختلفة، وأنماط بايتاتها الفريدة هي الأدلة التي تستخدمها أدوات الكشف.

الترميز الوصف مثال: € (علامة اليورو، U+20AC)
ASCII 7 بت، 128 محرفًا. هو الأصل. لا يمكنه تمثيل €. N/A
ISO-8859-15 8 بت، بايت واحد. تحديث لـ Latin-1 يشمل علامة اليورو. A4 (بايت واحد)
UTF-8 عرض متغير (1-4 بايت). هو المهيمن على الويب. متوافق مع ASCII. E2 82 AC (ثلاثة بايتات)
UTF-16 (BE) 2 أو 4 بايتات. شائع في أنظمة Windows و Java. BE = Big-Endian (النهاية الكبرى). 20 AC (بايتان)
Shift_JIS عرض متغير (1 أو 2 بايت). ترميز ياباني قديم. لا يمكنه تمثيل € في شكله القياسي. N/A

ترميز UTF-8 ذكي بشكل خاص. يستخدم عددًا متغيرًا من البايتات:

  • محارف ASCII (0-127) تستخدم بايتًا واحدًا فقط، مما يجعله مطابقًا لـ ASCII للنصوص الإنجليزية.
  • المحارف الأخرى تستخدم تسلسلات متعددة البايتات. البايت الأول يخبرك بعدد البايتات في التسلسل. على سبيل المثال، بايت يبدأ بـ 1110 يعني أنه بداية محرف من 3 بايتات. البايتات التالية يجب أن تبدأ بـ 10.
// تسلسل UTF-8 لـ € (U+20AC)
11100010 10000010 10101100
   ^        ^        ^
// بداية      بايت         بايت
// تسلسل من   استمرار     استمرار
// 3 بايتات

هذه البنية تجعل UTF-8 "متزامنًا ذاتيًا". إذا رأيت بايتًا يبدأ بـ 10، فأنت تعلم أنك في منتصف محرف، وليس في بدايته. هذا دليل ضخم لأدوات الكشف.

### خوارزمية الكشف (إنها لعبة تخمين)

إذًا، كيف تخمن أداة ما ترميز ملف غامض؟ تتبع قائمة تحقق، من الأكثر يقينًا إلى الأقل يقينًا.

  1. التحقق من وجود BOM (Byte Order Mark): الـ BOM هو محرف خاص غير مرئي (U+FEFF) يوضع في بداية الملف تمامًا للإعلان عن ترميزه. إنه أقوى دليل يمكنك الحصول عليه.

    • EF BB BF -> UTF-8
    • FE FF -> UTF-16 (Big Endian)
    • FF FE -> UTF-16 (Little Endian) إذا تم العثور على BOM، فعادة ما ينتهي عمل التحري.
  2. البحث عن تسلسلات بايت غير صالحة: إذا لم يكن هناك BOM، تختبر الأداة الملف وفقًا لقواعد الترميزات الشائعة، بدءًا من UTF-8. تقوم بمسح البايتات. هل تجد بايتًا يبدأ بـ 1110 لا يتبعه بايتان يبدآن بـ 10؟ إذا كان الأمر كذلك، فإن الملف ليس UTF-8 صالحًا. عملية الاستبعاد هذه فعالة جدًا. نفس المنطق ينطبق على أزواج UTF-16 البديلة (surrogate pairs) وقواعد الترميز الأخرى.

  3. تحليل التردد والاستدلال (Heuristics): إذا كان تيار البايتات صالحًا تحت عدة ترميزات (وهو ما يمكن أن يحدث، خاصة مع النصوص القصيرة)، ينتقل الكاشف إلى حيلته الأخيرة: التخمين المدروس. سيقوم بفك تشفير النص مؤقتًا باستخدام ترميزات شائعة مختلفة (windows-1252، Shift_JIS، إلخ) ويحلل النتيجة. هل فك التشفير كـ Shift_JIS ينتج عنه تردد عالٍ للمحارف اليابانية الشائعة؟ هل فك التشفير كـ ISO-8859-2 ينتج نصًا بولنديًا أو تشيكيًا معقولًا؟ يعتمد هذا على نماذج إحصائية للغات مختلفة. إنه ليس مثاليًا، ولكنه دقيق بشكل ملحوظ.

قصص من الواقع

### قضية تقرير CSV المشوه

محلل مالي في شركة في شيكاغو يتلقى تقرير المبيعات ربع السنوي من مكتبهم في طوكيو كملف CSV. ينقر نقرًا مزدوجًا لفتحه في Excel، ويصاب بالذعر. جميع أسماء العملاء والمنتجات باللغة اليابانية عبارة عن فوضى من المحارف المعلمة والرموز: 店長 بدلًا من 店長 (مدير المتجر). لساعات، يفترض أن الملف تالف.

أخيرًا، يلقي صديق مطور نظرة. يفتح الملف في أداة يمكنها فحص البايتات الأولية واكتشاف الترميزات. الحكم: تم حفظ الملف بترميز Shift_JIS، وهو ترميز قديم شائع في اليابان. لكن نسخة Excel الخاصة بالمحلل، المهيأة لنظام أمريكي، افترضت أن الملف هو windows-1252 (ترميز غربي شائع). كانت تطبق حلقة فك الشفرة الخاطئة. من خلال إخبار Excel صراحةً بفتح الملف باستخدام ترميز Shift_JIS، ظهرت المحارف بشكل مثالي.

الدرس: البيانات التي تعبر الحدود الدولية هي حقل ألغام لمشاكل الترميز. لا تفترض أبدًا أن الملف الذي تتلقاه يستخدم نفس الترميز الافتراضي لنظامك.

### المحرف الخفي الذي عطّل عملية الـ Build

مطور مبتدئ يعمل تحت ضغط موعد نهائي. يجد خوارزمية الفرز المثالية في منشور مدونة وينسخها ويلصقها مباشرة في سكربت Python الخاص به. يقوم بتشغيله محليًا، ويعمل بشكل لا تشوبه شائبة. يقوم بعمل commit للكود، ويفشل الـ continuous integration (CI) pipeline على الفور مع خطأ غامض SyntaxError: invalid character in identifier.

يحدق في الكود لمدة ساعة. يبدو مطابقًا تمامًا لما يعمل على جهازه. محبطًا، يطلب المساعدة من مطور أقدم. يقوم المطور الأقدم بتمكين "إظهار المحارف غير المرئية" في محرره. وهناك كان: محرف "مسافة عديمة العرض" (zero-width space) واحد وغير مرئي (U+200B) يختبئ بين اسمي متغيرين، تم نسخه من تنسيق HTML الأنيق للمدونة. محرره الحديث والواعي بـ UTF-8 عرضه بشكل غير مرئي، لكن المدقق (linter) الأقدم والأكثر صرامة على سيرفر الـ build رآه كمحرف غير قانوني وأطلق خطأ.

الدرس: ما تراه ليس دائمًا ما تحصل عليه. محارف يونيكود غير المرئية حقيقية ويمكن أن تسبب أخطاءً صعبة التصحيح بشكل يثير الجنون في قواعد الأكواد.

### قاعدة بيانات الإيموجيز المحطمة

شركة ناشئة تطلق تطبيقًا اجتماعيًا جديدًا. يحقق نجاحًا كبيرًا، لكن تقارير الأخطاء تتدفق. يشتكي المستخدمون من أنه كلما استخدموا إيموجي 👍 أو محرفًا معلمًا مثل naïve، يتم حفظ منشورهم مع محارف ?. التطبيق يقوم حرفيًا باستبدال تعابيرهم بعلامات استفهام.

يقوم فريق التطوير بالتحقيق في الـ stack. الواجهة الأمامية (frontend) ترسل JSON بترميز UTF-8، وهذا صحيح. الخدمة الخلفية (backend) تتعامل معه على أنه UTF-8. المشكلة في قاعدة البيانات. أثناء الإعداد، استخدموا مجموعة المحارف الافتراضية latin1 لقاعدة بيانات MySQL الخاصة بهم. latin1 هو ترميز أحادي البايت؛ ليس لديه طريقة لتخزين تسلسل الـ 4 بايتات لإيموجي الإعجاب. عندما تلقت قاعدة البيانات محرفًا لا يمكنها تخزينه، استبدلته بـ ? كحل بديل. تضمن الإصلاح ترحيلًا مؤلمًا لقاعدة البيانات إلى مجموعة المحارف utf8mb4، التي توفر دعمًا كاملًا ليونيكود.

الدرس: يجب أن يتحدث مسار البيانات بأكمله، من متصفح المستخدم إلى قرص قاعدة البيانات، نفس الترميز. حلقة ضعيفة واحدة ستفسد بياناتك.

أخطاء وشراك شائعة

  • افتراض أن كل شيء هو UTF-8. بينما هي اللغة المشتركة للويب، إلا أنها ليست عالمية. التطبيقات الأصلية، الأنظمة القديمة، وتصدير البيانات من أدوات مثل Excel غالبًا ما تستخدم ترميزات إقليمية أقدم. تحقق دائمًا، لا تفترض أبدًا.
  • الخلط بين Unicode و UTF-8. ليسا نفس الشيء. يونيكود هو المعيار المجرد (خريطة المحارف). UTF-8 هو ترميز ملموس (تنسيق التخزين). القول "هذا الملف يونيكود" غير دقيق؛ أنت تقصد أنه من المحتمل أن يكون UTF-8 أو UTF-16 أو UTF-32.
  • نسيان الـ BOM. عندما تقرأ ملف UTF-8 يحتوي على BOM، يجب عليك إزالة تلك البايتات الثلاثة الأولى ( في Latin-1). إذا لم تفعل، يمكن أن تظهر كخربشات في بداية المحتوى الخاص بك، أو تعطل محللات JSON/XML، أو تسبب فشل هيدرز HTTP.
  • استخدام utf8 بدلًا من utf8mb4 في MySQL/MariaDB. هذا فخ كلاسيكي في قواعد البيانات. مجموعة المحارف utf8 في MySQL هي تطبيق قديم ومعطوب يدعم فقط ما يصل إلى 3 بايتات لكل محرف. هذا يعني أنه لا يمكنه تخزين العديد من الإيموجيز وبعض الرموز الأخرى. أنت دائمًا تقريبًا تريد استخدام utf8mb4.
  • الترميز المزدوج (Double-encoding). هذه مشكلة خبيثة بشكل خاص حيث تأخذ نصًا هو بالفعل UTF-8، لكنك تخبر برنامجًا عن طريق الخطأ أنه Latin-1. ثم يأخذ البرنامج بيانات "Latin-1" هذه ويقوم بتحويلها "بكل سرور" إلى UTF-8. النتيجة هي قمامة مثل é لـ é، وهو تمثيل UTF-8 لتمثيل UTF-8 لمحرف. غالبًا ما يكون من الصعب جدًا عكس هذه العملية.

لماذا يجب أن يكون على رادارك

إذا كنت تكتب كودًا يلمس ملفًا نصيًا، أو API، أو قاعدة بيانات، أو مدخلات مستخدم، فأنت تتعامل مع ترميز المحارف. إنه ليس موضوعًا غامضًا "من الجيد معرفته"؛ إنه جزء أساسي من سلامة البيانات.

يجب أن تفكر في الترميز كلما:

  • قرأت أو كتبت ملفات على القرص (.csv, .txt, .json, .xml, etc.).
  • تلقيت بيانات من طلب HTTP أو أرسلت استجابة HTTP.
  • اتصلت بقاعدة بيانات وقمت بالاستعلام منها.
  • عالجت نصًا أرسله مستخدمون من جميع أنحاء العالم.
  • عملت مع أنظمة قديمة أو بيانات من أطراف ثالثة.

الخطأ في الترميز يؤدي إلى تلف بيانات خفي، وأخطاء محبطة، ومستخدمين غير سعداء. فهمه هو علامة على المطور المحترف الذي يهتم ببناء برامج قوية وجاهزة للعالمية.

تعمق أكثر

انتهينا من النظرية. حان وقت التطبيق — 100% في متصفحك.

جرّب الأداة: Text Encoding Detector