المستوى: مبتدئ · وقت القراءة: حوالي 7 دقائق · تحتاج معرفة بسيطة بأي لغة برمجة
ليه اسمك بيظهر رموز غريبة زي "Ù…Ø±ØØ¨Ø§"؟ فهم الترميز وUTF-8 من الصفر
بعد المقال ده هتعرف بالظبط ليه النص العربي بيتحوّل أحيانًا لرموز غريبة، وهتقدر تصلّح المشكلة في دقيقة بدل ما تقعد ساعة تخبط. الحكاية كلها في كلمة واحدة: الترميز (encoding).
المشكلة باختصار
فتحت ملف CSV فيه أسماء عربية على Excel، فلقيت "أحمد" اتحولت لـ "Ø£ØÙ…د". أو خزّنت تعليق في قاعدة البيانات، ورجعلك مليان علامات استفهام. ده مش عطل في جهازك، وده مش فيروس. الاسم العلمي للظاهرة دي هو mojibake (موجيباكي)، وسببها واحد بالظبط: النص اتكتب بترميز، واتقرأ بترميز تاني.
الحكاية بمثال بسيط قبل الكلام العلمي
تخيّل إنك بتبعت رسالة سرية لصاحبك بشيفرة: كل رقم بيقابل حرف. أنت كتبت الرسالة بجدول شيفرة معيّن، ولفّيتها في ورقة. لو صاحبك فكّها بنفس الجدول اللي أنت استخدمته، هيقرأ الكلام مظبوط. لكن لو مسك جدول تاني مختلف، الأرقام نفسها هتترجم لحروف تانية خالص، وهيطلعله كلام مبهم.
الكمبيوتر بيعمل نفس الحاجة بالظبط. هو مش بيخزّن "حروف"، هو بيخزّن أرقام (بايتات). الترميز هو "جدول الشيفرة" اللي بيقول: الرقم ده يساوي الحرف ده. لو خزّنت بجدول UTF-8 وقريت بجدول latin-1، بتطلعلك رموز غريبة. نفس فكرة الرسالة السرية.
الكلام العلمي: من الحرف للبايت
أي حرف في الدنيا له رقم موحّد اسمه code point في معيار Unicode. الحرف A رقمه U+0041، وحرف الميم "م" رقمه U+0645. لكن الرقم ده لازم يتحوّل لبايتات عشان يتخزّن أو يتبعت في الشبكة. العملية دي اسمها encoding، وأشهر طريقة ليها هي UTF-8.
في UTF-8، الحروف الإنجليزية (ASCII) بتاخد بايت واحد لكل حرف، والحروف العربية بتاخد بايتين لكل حرف. عشان كده لما تقيس طول كلمة عربية بالبايت هتلاقيه ضعف عدد حروفها تقريبًا. جرّب بنفسك:
جرّبها بنفسك: 6 أسطر بايثون توريك المشكلة والحل
الكود ده بيوضح ليه mojibake بيحصل، وإزاي يترجع النص صح لما تستخدم نفس الترميز:
text = "مرحبا"
# encode: نحوّل النص لبايتات باستخدام UTF-8
data = text.encode("utf-8")
print(len(text), "حروف") # 5 حروف
print(len(data), "بايت") # 10 بايت (كل حرف عربي = بايتين)
# decode صح: بنفس الترميز
print(data.decode("utf-8")) # مرحبا ← رجع سليم
# decode غلط: بترميز تاني = mojibake
print(data.decode("latin-1")) # Ù…Ø±ØØ¨Ø§ ← رموز غريبة
ركز في النتيجة: نفس الـ 10 بايت بالظبط. الفرق الوحيد هو "الجدول" اللي قريت بيه. UTF-8 رجّع الكلمة، وlatin-1 حوّلها لرموز. المشكلة مش في البيانات، المشكلة في اختيار الترميز وقت القراءة.
سيناريو واقعي: ليه Excel بيخرب الملف
لو عندك متجر بيصدّر ملف CSV فيه 5000 اسم عميل عربي، وفتحته بالدبل-كليك على Excel، غالبًا هيقرأه بترميز Windows-1256 مش UTF-8، فتلاقي الأسماء كلها اتخربت. الحل مش تعديل الملف، الحل إنك تقول لـ Excel يقراه UTF-8: افتحه من Data ثم From Text/CSV واختَر File Origin: UTF-8. نفس الملف، نفس البايتات، بس بترميز صح.
الـ trade-off: UTF-8 مقابل UTF-16
UTF-8 هو الافتراضي على الويب (أكتر من 98% من صفحات الإنترنت بتستخدمه حسب W3Techs). المكسب: النصوص الإنجليزية والرموز بتاخد مساحة أقل، وهو متوافق مع ASCII القديم. الثمن: كل حرف عربي بياخد بايتين بدل ما ياخد بايت واحد في ترميزات قديمة زي Windows-1256. لو عندك نص عربي بحت وضخم جدًا وعايز أقصى ضغط، ممكن UTF-16 أو ضغط gzip يبقوا أفضل، بس التعقيد اللي هيجيلك مش بيستاهل غالبًا. الافتراض هنا إنك بتبني تطبيق ويب عادي، وفي الحالة دي UTF-8 هو الاختيار الصح بدون تفكير.
متى متشغلش بالك
لو تطبيقك كله UTF-8 من أوله لآخره — قاعدة البيانات، والـ API، والملفات، وترويسة الصفحة <meta charset="utf-8"> — فأنت مش هتشوف mojibake أصلًا، ومش محتاج تفكر في الموضوع ده تاني. المشكلة بتظهر بس عند الحدود: لما بيانات تعدّي من نظام لنظام بترميز مختلف (استيراد ملف قديم، قاعدة بيانات charset بتاعها latin1، أو API خارجي مش بيقول ترميزه). ركّز طاقتك على النقط دي بس.
الخطوة التالية
افتح إعداد قاعدة البيانات بتاعتك دلوقتي وشوف الـ charset. لو لقيته latin1، ده قنبلة موقوتة. في MySQL غيّره لـ utf8mb4 (مش utf8 القديم، لأن utf8mb4 هو اللي بيدعم كل رموز اليونيكود بما فيها الإيموجي). ابدأ بأمر واحد للتشخيص: SHOW VARIABLES LIKE 'character_set_database'; وشوف النتيجة.
المصادر
- توثيق Python الرسمي — Unicode HOWTO: docs.python.org/3/howto/unicode.html
- معيار Unicode الرسمي: home.unicode.org
- مواصفة UTF-8 (RFC 3629): datatracker.ietf.org/doc/html/rfc3629
- Joel Spolsky — The Absolute Minimum Every Developer Must Know About Unicode: joelonsoftware.com
- إحصاء استخدام UTF-8 على الويب — W3Techs: w3techs.com/technologies/details/en-utf8
- MySQL — utf8mb4 والفرق عن utf8: dev.mysql.com