المستوى: مبتدئ — المقال ده موجّه للمبتدئين. لو سبق وفتحت ملف أو رسالة أو صفحة ولقيت اسمك العربي اتحوّل لرموز غريبة، هتعرف هنا ليه بالظبط، وتقدر تصلّحها في دقيقة.
ليه اسمك بالعربي بيظهر «Ø£Ù‡Ù„ا»؟ الحكاية اسمها الترميز
الكمبيوتر مبيعرفش حروف. بيعرف أرقام بس. أي حرف بتكتبه بيتحوّل لرقم، والرقم بيتخزّن كبايتات. لو الجهاز اللي كتب النص والجهاز اللي قراه اتفقوا على نفس «جدول الأرقام»، الكلام يظهر صح. لو اختلفوا، تطلع الرموز الغريبة دي. المشكلة مش في اللغة العربية، ولا في جهازك. المشكلة في اختلاف الترميز بين الكتابة والقراءة.
المشكلة باختصار
عندك سطر مكتوب صح: «أهلاً». تبعته لزميلك أو تصدّره في ملف، يوصله «Ø£Ù‡Ù„اً». الحروف اتبدّلت بحاجة ملهاش معنى. الاسم العلمي للظاهرة دي هو mojibake. وبتحصل لأن النص اتكتب بترميز، واتقرا بترميز تاني. وده مهم لأي حد بيشتغل بالعربي: أسماء، عناوين، رسائل، ملفات CSV، قواعد بيانات. غلطة ترميز واحدة تفسد آلاف الصفوف.
الفكرة الأول بمثال: الشفرة السرية بين صاحبين
تخيّل إنت وصاحبك عملتوا شفرة: كل حرف ليه رقم. A=1، B=2، وهكذا. لو بعتّله «2 1 20»، هو يفكّها لـ «B A T». تمام، لأنكم الاتنين ماسكين نفس الورقة.
دلوقتي تخيّل صاحبك مسك ورقة تانية، فيها A=100 وB=200. هيقرا نفس الأرقام ويطلعله كلام مختلف تمامًا. مفيش حد غلط في العملية الحسابية، بس الجدول اختلف، فالنتيجة بقت هباب. الكمبيوتر بيعمل نفس الحكاية بالظبط: «الورقة» دي اسمها الترميز (encoding).
الشرح العلمي: من الحرف للبايت
خلينا نفكّها بدقة على تلات مستويات:
- نقطة الكود (code point): معيار Unicode أعطى لكل حرف في كل لغات الدنيا رقمًا فريدًا. الحرف A رقمه U+0041، والحرف س رقمه U+0633. ده «الهوية» الثابتة للحرف.
- الترميز (encoding): إزاي نخزّن الرقم ده كبايتات فعليًا. UTF-8 هو الطريقة الأشهر. بيستخدم بايت واحد للحروف اللاتينية (نفس ASCII القديم)، وبايتين لأغلب الحروف العربية، وحتى 4 بايتات للإيموجي.
- البايتات: الأرقام اللي بتتخزّن فعلًا على القرص أو بتتبعت على الشبكة.
فالحرف A في UTF-8 بايت واحد قيمته 65 (أو 0x41). والحرف س بايتين قيمتهم 0xD8 و0xB3. القارئ لازم يعرف إن دول UTF-8 عشان يرجّعهم حروف صح.
جرّبها بنفسك: كود بايثون يوريك المشكلة والحل
انسخ الكود ده وشغّله. هتشوف الرموز الغريبة بتتولد قدامك، وبعدين تتصلّح:
text = "أهلاً"
# 1) الترميز الصح: نحوّل الحروف لبايتات UTF-8
data = text.encode("utf-8")
print(data) # b'\xd8\xa3\xd9\x87\xd9\x84\xd8\xa7\xd9\x8b'
print(len(text), "رمز /", len(data), "بايت") # 5 رمز / 10 بايت
# 2) القراءة الغلط: نفتح نفس البايتات كأنها Windows-1252
print(data.decode("cp1252")) # أهلاً <-- الرموز الغريبة
# 3) الحل: اقرأ بنفس ترميز الكتابة
print(data.decode("utf-8")) # أهلاً
لاحظ حاجة مهمة: «أهلاً» فيها 5 رموز بس بتاخد 10 بايت. عشان كده لو بتقصّ نص عربي بالبايت مش بالحرف، ممكن تقطع حرف من نُصّه وتكسّر النص. القص لازم يكون على مستوى الحرف.
سيناريو واقعي: 50 ألف اسم اتخربوا
عندك نظام بيصدّر ملف CSV فيه 50,000 اسم عميل بالعربي، والتصدير بترميز UTF-8. حد فتح الملف على نسخة قديمة من Excel بتفترض ترميز الويندوز المحلي بدل UTF-8. النتيجة: الـ 50 ألف صف كلهم بقوا رموز غريبة. مفيش داتا ضاعت فعلًا، البايتات سليمة، بس العرض غلط. الحل إنك تستورد الملف مع تحديد UTF-8 صراحةً، أو تضيف علامة BOM في أول الملف عشان Excel يتعرّف عليه. الفرق بين ساعة إحباط وبين نص دقيقة: سطر واحد بيحدد الترميز.
الـ trade-off: ليه UTF-8 مش UTF-16
UTF-8 مش الوحيد. فيه UTF-16 كمان. الفرق في التكلفة:
- UTF-8: الحروف اللاتينية والأرقام والرموز البرمجية بايت واحد. النص الإنجليزي والكود بيطلعوا أصغر. العربي بايتين.
- UTF-16: كل حرف بايتين على الأقل. العربي بايتين (زي UTF-8)، بس الإنجليزي بقى بايتين بدل واحد، يعني ملف أكبر.
بالأرقام: ملف نص إنجليزي حجمه 1 ميجابايت في UTF-8 بيبقى قرابة 2 ميجابايت في UTF-16. المكسب مع UTF-8: توافق ممتاز مع كل الأنظمة القديمة وحجم أصغر للمحتوى المختلط. الخسارة: النص العربي أو الصيني الخالص ممكن يبقى أكبر شوية من UTF-16. الافتراض هنا إن مشروعك محتوى مختلط أو ويب، وده اللي بيخلّي UTF-8 المعيار الفعلي لأكثر من 98% من مواقع الإنترنت.
متى لا تشغّل بالك
لو مشروعك UTF-8 من أوله لآخره — قاعدة البيانات utf8mb4، الملفات UTF-8، وترويسة الـ HTTP فيها charset=utf-8 — فإنت مش هتقابل المشكلة دي أصلًا. كمان لو بتتعامل مع نص إنجليزي/ASCII بحت، الترميز نادرًا ما هيبوّظ حاجة. المشكلة بتظهر بس عند الجسور بين أنظمة مختلفة: تصدير/استيراد، بريد قديم، أو قاعدة بيانات متظبطة على latin1.
الخطوة التالية
افحص ترميز أهم ملف عندك دلوقتي. على لينكس أو ماك: file -I file.csv هيقولك الـ charset. اتأكد إن قاعدة بياناتك utf8mb4 مش latin1، وإن أي رد HTTP بتطلعه فيه Content-Type: text/html; charset=utf-8. لو لقيت أي حاجة مش UTF-8، ثبّتها على UTF-8 وخلاص.
المصادر
- معيار Unicode الرسمي — unicode.org/standard (تعريف نقاط الكود).
- RFC 3629 — تعريف UTF-8 كمعيار إنترنت — rfc-editor.org/rfc/rfc3629 (عدد البايتات لكل حرف).
- توثيق بايثون الرسمي عن Unicode — docs.python.org — Unicode HOWTO (دوال encode/decode).
- إحصاء استخدام الترميزات على الويب — w3techs.com (نسبة UTF-8 أكثر من 98%).