ما الذي يُحسب حرفًا واحدًا؟
أربعة أنظمة مختلفة تعدّ النص نفسه بأربع طرق مختلفة. وفي النصوص الإنجليزية تتفق جميعها، ولهذا تبقى المشكلة خفية حتى اليوم الذي لا تتفق فيه.
آخر مراجعة
رمز تعبيري واحد، وأربع إجابات
خذ رمز الإبهام المرفوع بلون بشرة محدد، أو رمز العائلة. عُدّه بأربع طرق فتحصل على أربعة أرقام، ولا أحد منها خاطئ.
القارئ يرى حرفًا واحدًا. شيء واحد، وضغطة واحدة على مفتاح Backspace لحذفه.
التعبير النمطي قد يرى سبعة. فالرمز مبني من عدة نقاط ترميز تربطها وصلات غير مرئية — رمز تعبيري أساسي، ثم معدِّل، ثم وصلة، ثم رمز تعبيري آخر، وهكذا.
JavaScript تُبلغ عن أحد عشر. فهي تخزّن النص في وحدات من 16 بت، وكل ما يقع خارج النطاق الأساسي يشغل وحدتين، ولذلك قد تُحسب كل نقطة ترميز من تلك مرتين.
عمود قاعدة البيانات يرى خمسة وعشرين بايتًا. فعند الترميز بـ UTF-8 للتخزين، تشغل كل نقطة ترميز حتى أربعة بايتات.
في النصوص الإنجليزية العادية تتطابق الأرقام الأربعة. ولهذا بالضبط تبقى المشكلة خفية إلى أن يُدخل أحدهم اسمًا بحرف معلَّم، أو جملة باليابانية، أو رمزًا تعبيريًا واحدًا — فيبدأ حقل عمل بلا مشكلات ثلاث سنوات في اقتطاع البيانات.
أي رقم يقصده الحدّ
السؤال العملي ليس أبدًا «كم طول هذا النص»، بل «ما الذي يفرض الحدّ»، وهناك أربع إجابات شائعة.
عمود قاعدة البيانات المعرَّف بنوع VARCHAR يعدّ البايتات في معظم المحركات. ولهذا فإن حقلًا يقبل 255 حرفًا إنجليزيًا بسهولة يرفض عددًا أقل بكثير من الأحرف اليابانية — ثلاثة بايتات لكل منها — ولهذا أيضًا لا يتسع أحيانًا اسم فيه حرف معلَّم بينما كانت نسخته العادية تتسع.
الرسالة النصية القصيرة (SMS) تتسع لـ 160 حرفًا بأبجديتها الخاصة ذات السبع بتات، وتنخفض إلى 70 حرفًا لكل رسالة بمجرد أن يقع حرف واحد خارجها. فعلامة اقتباس منحنية واحدة ملصوقة من معالج نصوص، أو رمز تعبيري واحد، قد تحوّل رسالة من جزء واحد إلى ثلاثة أجزاء وتضاعف ما تدفعه ثلاث مرات.
أداة التحقق من النماذج في JavaScript تعدّ وحدات UTF-16 في الغالب، ولهذا قد يرفض حقل يقول 280 حرفًا نصًا يبدو أقصر بكثير إذا كان مليئًا بالرموز التعبيرية.
الإنسان يعدّ ما يراه، وهذا هو التعريف الوحيد المهم للعنوان الرئيسي أو وسم العنوان (title) أو أي شيء له مساحة بصرية محدودة.
أين تختلف الأعداد
معرفة المدخلات التي تسبب المشكلات أنفع من معرفة النظرية، لأن هذه المدخلات يمكن توقعها.
الرموز التعبيرية، ولا سيما المركّبة منها — ألوان البشرة، والعائلات، والأعلام، والمهن. فالعلم حرفان من أحرف المؤشرات الإقليمية، والمهنة عادةً شخص ووصلة وأداة.
الأحرف المعلَّمة والعلامات المركِّبة. يمكن كتابة الحرف é كنقطة ترميز واحدة، أو كحرف e تتبعه علامة نبرة مركِّبة. يبدوان متطابقين، لكنهما يُرتَّبان بشكل مختلف، ولا يتساويان عند المقارنة، ويُعدّان بشكل مختلف — والشكلان كلاهما موجودان في البيانات الحقيقية، وكثيرًا ما يكونان في العمود نفسه.
الأنظمة الكتابية غير اللاتينية. كل حرف صيني أو ياباني أو كوري يشغل ثلاثة بايتات في UTF-8. أما الهندية والتايلاندية والتاميلية والعربية فتكوّن عناقيد يدركها القارئ كوحدات مفردة، بينما يبلغ طول كل منها عدة نقاط ترميز.
الرموز الرياضية والموسيقية، وهي تقع خارج النطاق الأساسي، ولذلك تُحسب مرتين في UTF-16.
ما الذي تفعله حيال ذلك
عُدّ ما يعدّه الحدّ. عدّاد يعرض الأرقام الأربعة كلها يجيب عن السؤال مباشرة، وهذا أسرع من التفكير فيه. وفي الكود، استخدم الدالة المناسبة: Intl.Segmenter في JavaScript تعدّ ما يراه القارئ، وlen(s.encode("utf-8")) في Python تعدّ البايتات، واستخدم mb_strlen بدلًا من strlen في PHP.
أصلح العمود بدلًا من النموذج. إذا كان حقل قاعدة البيانات هو القيد، فالحل الدائم في المصدر: عرّفه بنوع utf8mb4 في MySQL أو text في PostgreSQL. فترميز «utf8» القديم في MySQL معروف بأنه لا يتجاوز ثلاثة بايتات للحرف، ولا يستطيع تخزين رمز تعبيري إطلاقًا — وهو فخ قديم اقتطع بصمت قدرًا كبيرًا من البيانات الحقيقية. أما العدّ الدقيق في النموذج فهو حل مؤقت لعمود كان ينبغي تعريفه بشكل مختلف.
وحّد الصيغة عند الإدخال. تحويل النص إلى صيغة موحّدة واحدة عند نقطة الإدخال يعني أن الكتابتين المختلفتين للحرف é تصبحان واحدة، فتبدأ المقارنة والترتيب والعدّ كلها في الاتفاق. ولكل لغة برمجة دالة لذلك، وتنفيذه مرة واحدة عند الحدود أسهل بكثير من التعامل مع الشكلين في كل مكان.
حالة مشابهة: base64
تستحق الذكر لأنها تُحدث المفاجأة نفسها. ترميز البيانات بـ base64 يأخذ ثلاثة بايتات في كل مرة ويكتبها كأربعة أحرف، ولذلك تكون النتيجة أكبر بنحو الثلث — وهذه حسبة رياضية لا قلة كفاءة. فمرفق حجمه 6 MB يصبح نحو 8 MB من النص، ولهذا قد يُرفض ملف يقل حجمه بوضوح عن الحدّ بمجرد ترميزه للإرسال.
والحسبة نفسها تفسّر لماذا تُرتدّ مرفقات البريد الإلكتروني عند حدود يبدو أنها تلتزم بها. إذا كنت تقيس شيئًا مقابل حدّ أقصى، فقِس الصيغة المرمّزة.
الأسئلة الشائعة
لماذا يرفض حقلي ذو الـ 255 حرفًا نصًا أقصر من ذلك؟
على الأرجح لأنه يعدّ البايتات لا الأحرف. فالأحرف المعلَّمة تشغل بايتين في UTF-8، والأحرف الصينية واليابانية والكورية تشغل ثلاثة، ولذلك قد تعني 255 بايتًا 85 حرفًا يابانيًا فقط. وتعريف العمود بنوع utf8mb4 أو text يصلح المشكلة كما ينبغي.
هل يكلّفني رمز تعبيري واحد فعلًا ثلاث رسائل SMS؟
قد يحدث ذلك. فالرسالة التي لا تحتوي إلا على أحرف من أبجدية GSM تتسع لـ 160 حرفًا في كل جزء، وحرف واحد خارجها يحوّل الرسالة كلها إلى ترميز من 70 حرفًا. ولذلك تصبح رسالة من 150 حرفًا فيها رمز تعبيري واحد ثلاثة أجزاء بدلًا من جزء واحد.
أي عدد أستخدم لوسم العنوان (title)؟
لا أحد منها بدقة — فمحركات البحث تقتطع العنوان وفق عرضه بالبكسل لا وفق عدد أحرفه، ولذلك يُقصّ عنوان من الأحرف الكبيرة العريضة أسرع من عنوان من الأحرف الصغيرة الضيقة. ونحو 60 حرفًا هي القاعدة التقريبية المعتادة، وهي إرشاد لا حدّ.
لماذا لا يتطابق نصّان يبدوان متطابقين؟
عادةً لأن حرفًا معلَّمًا مكتوب بطريقتين مختلفتين — كنقطة ترميز واحدة في أحدهما، وكحرف أساسي مع علامة مركِّبة في الآخر. توحيد صيغة النصين قبل المقارنة يجعلهما متطابقين، ويستحق ذلك أن يُنفَّذ عند نقطة دخول البيانات إلى نظامك.
هل عدد الكلمات أكثر ثباتًا من عدد الأحرف؟
في الإنجليزية، غالبًا. لكن ليس في كل اللغات: فالصينية واليابانية لا تفصلان الكلمات بمسافات، وكذلك التايلاندية، ولذلك يتطلب عدّ الكلمات في هذه الأنظمة الكتابية تقسيمًا للنص، وتعطي الأدوات المختلفة إجابات مختلفة.