فاحص محارف يونيكود
يفكّك النص إلى نقاطه الرمزية بأسمائها وفئاتها وكتلها وترميزاتها، ويؤشّر على المحارف الخفية ومحارف bidi والمحارف المتشابهة.
ما الذي تفعله هذه الأداة
الصق أي نص فيعود مفكَّكًا إلى المحارف المفردة التي يتألف منها فعلًا. ويحصل كل محرف على اسمه في يونيكود، ورقم U+ الخاص به، وأي صنف من المحارف هو، وإلى أي نظام كتابة وأي كتلة ينتمي، وكم بايتًا يشغل في UTF-8 و‑UTF-16، وأي تسلسل هروب يتطلبه في ستة صيغ مختلفة.
ويأتي معظم الناس إلى هنا لأن شيئًا ما لا يستقيم. فالسلسلة أطول مما تبدو، أو قيمتان تظهران متطابقتين وترفضان أن تتساويا، أو اسم مستخدم رُفض بسبب محارف تبدو حروفًا عادية، أو سطر شفرة يُقرأ خلاف ما يفعل. وللأربعة الشكل نفسه: محرف يفعل شيئًا لا تُظهره الشاشة.
المحارف والنقاط الرمزية والحروف المرئية
لكلمة «محرف» ثلاثة معانٍ مختلفة على الأقل، والخلط بينها هو منبع أكثر اللبس حول يونيكود. فالنقطة الرمزية قيمة واحدة في معيار يونيكود، تُكتب U+0041 أو U+1F600. أما الحرف المرئي فهو ما يعدّه القارئ محرفًا واحدًا. وكثيرًا ما لا يكونان العدد نفسه.
- حرف «a» البسيط هو حرف مرئي واحد ونقطة رمزية واحدة ووحدة UTF-16 واحدة — الكل متفق.
- U+00E9، وهو é المركَّب مسبقًا، حرف مرئي واحد ونقطة رمزية واحدة ووحدة UTF-16 واحدة.
- U+0065 U+0301، الحرف نفسه مكتوبًا e مع علامة تشكيل ملحقة، حرف مرئي واحد لكنه نقطتان رمزيتان ووحدتا UTF-16.
- U+1F600، الوجه المبتسم، حرف مرئي واحد ونقطة رمزية واحدة لكنه وحدتا UTF-16 — فهو يقع فوق الـ BMP، ولذا يخزّنه JavaScript زوجًا بديلًا.
- وإيموجي العائلة حرف مرئي واحد وخمس نقاط رمزية وثماني وحدات UTF-16: ثلاثة أشخاص يربطهم رابطان خفيان.
وإيموجي العائلة هو الحالة التي توقع الناس. فهو يبدو شيئًا واحدًا، ويبلّغ JavaScript عن طول 8، وعمود قاعدة بيانات سعته 5 محارف لا يسعه. وهذه الأداة تجمع النقاط الرمزية تحت الحرف المرئي الذي تبنيه، فتظهر القراءتان معًا بدل أن يوفَّق بينهما ذهنيًا.
المحارف التي لا تُرى
عدد مدهش من محارف يونيكود لا يرسم شيئًا البتة. فهي موجودة للتحكم في سلوك النص من حولها، ولأنها لا تترك أثرًا تنجو من النسخ واللصق والمراجعة دون أن ينتبه أحد. وهذه هي التي تشير إليها الأداة بدل أن تكتفي بسردها:
- المسافة والرابط والفاصل معدومة العرض (U+200B، U+200D، U+200C) — بلا عرض وبلا أثر، وهي تكسر كل مقارنة سلاسل تمسّها.
- الواصلة اللينة (U+00AD) — اقتراح بموضع جواز قطع الكلمة، خفية حتى يقع القطع.
- المسافة غير الفاصلة (U+00A0) — تبدو مطابقة تمامًا للمسافة وهي محرف آخر، ولهذا تعمّر طويلًا في ملفات الإعداد.
- علامة ترتيب البايتات (U+FEFF) — كثيرًا ما تبقى في أول الملف، فتصير محرفًا أول خفيًا للقيمة الأولى.
- محارف تحكّم bidi وتجاوزاتها (من U+202A إلى U+202E، ومن U+2066 إلى U+2069) — تعيد ترتيب النص من حولها.
ومحارف تحكّم bidi تستحق ذكرًا خاصًا. فقد أُضيفت ليختلط العربية والعبرية بالنص اللاتيني اختلاطًا صحيحًا، وهي تؤدي هذا العمل جيدًا. لكن تجاوزًا يوضع داخل تعليق أو داخل سلسلة نصية قد يجعل سطر شفرة يُعرض بترتيب مغاير تمامًا للترتيب الذي يقرأه المترجِم — أي أن مراجعًا قد يجيز شفرة تفعل شيئًا آخر بالكلية. ويُعرف هذا الصنف من الحيل باسم Trojan Source، ولهذا تؤشّر الأداة على كل محرف تحكّم bidi على حدة بمعزل عن سائر المحارف الخفية.
المحارف المتشابهة واختلاط الكتابات
يحوي يونيكود محارف كثيرة تطابق حروف ASCII بصريًا وليست إياها. فالـ а الكيريلية والـ ο اليونانية والـ a اللاتينية تشغل نقاطًا رمزية مختلفة وتُرسم متماثلة في أكثر الخطوط. ونطاق أو اسم مستخدم مبني منها يبدو صحيحًا ويشير إلى موضع آخر.
والتأشير على كل شبيه غير ASCII عديم الجدوى: فسيصبغ بالأحمر كل كلمة روسية أو يونانية أو عبرية، والتحذير الذي ينطلق على النص العادي تحذير يتعلم الناس تخطّيه. ولذا فالقاعدة هنا هي التي يستعملها معيار الأمن في يونيكود: الكلمة مريبة حين تأتي حروفها من أكثر من نظام كتابة واحد:
- «paypal.com» مكتوبة كلها بحروف لاتينية: لا شيء يُقال عنها.
- الكلمة نفسها بحرفَي ر و ا كيريليَّين قبل «ypal» اللاتينية: كلمة واحدة ونظاما كتابة، فتُؤشَّر.
- كلمة روسية كاملة بالكيرلية: نظام كتابة واحد ونص عادي، فلا تُؤشَّر.
- جملة يابانية تستعمل الهان والهيراغانا والكاتاكانا معًا: ثلاث كتابات ونظام كتابة واحد، فلا تُؤشَّر.
والحالة الأخيرة هي سبب وجوب التدقيق في القاعدة. فاليابانية تُكتب بثلاث كتابات في آنٍ واحد، والكورية تخلط اثنتين، ولذا فاختبار ساذج من نوع «أكثر من كتابة أمر مريب» كان سيعلن كل جملة يابانية هجومًا. أما التوليفات التي هي حقًا نظام كتابة واحد فتُعامَل معاملة الواحد، وهذا ما يبقي للتحذير معناه.
التسوية، أو لماذا تختلف سلسلتان متطابقتان
بعض المحارف يمكن كتابتها بأكثر من طريقة. فالحرف é إما النقطة الرمزية المفردة U+00E9 وإما الزوج U+0065 U+0301: حرف e بسيط تتلوه علامة حادّة ملحقة. وكلاهما يُعرض متطابقًا. ولا أحدهما خطأ. وليسا متساويين.
والتسوية هي عملية اختيار إملاء واحد، ولها أربع صيغ. فـ NFC تركّب حيثما أمكن وهي ما تفترضه الويب افتراضًا؛ و‑NFD تفكّك عوضًا عن ذلك. وصيغتا الـ K تمضيان أبعد وتطويان كذلك محارف التوافق — فالـ A كاملة العرض تصير A بسيطة، والرابطة fi تصير fi — وهو مفيد للبحث والمطابقة ومُفقِد للمعلومات في التخزين.
واللوحة هنا تُظهر الصيغ الأربع لما تلصقه وتؤشّر على ما يختلف منها عن المدخل. فإن لم يختلف شيء فالنص مسوّى أصلًا، والتفاوت الذي تطارده في موضع آخر. وإن اختلف بعضها فقد وجدته.
الأسماء والفئات والكتابات والكتل
يحمل كل محرف مُسنَد أربعة عناصر هوية، وهي تجيب عن أسئلة مختلفة. فالاسم هو المحرف نفسه. والفئة العامة تقول أي صنف من الأشياء هو: حرف صغير، أو علامة ملحقة، أو رمز عملة، أو محرف تحكّم بالتنسيق. والكتابة هي نظام الكتابة الذي ينتمي إليه. والكتلة هي مدى النقاط الرمزية الذي أُسنِد فيه، وهذه حقيقة تنظيمية لا لغوية.
ويسهل الخلط بين الكتلة والكتابة، وكثيرًا ما تتباينان. فالحروف اللاتينية تعيش في نصف دزينة من الكتل على الأقل، والكتلة الواحدة قد تضم محارف من كتابات عدة. فحين تريد أن تعرف «أي أبجدية هذه» فالجواب هو الكتابة؛ وحين تريد أن تعرف «أين يقع هذا في المعيار» فهو الكتلة.
والأسماء والكتابات والكتل تُعرض هنا بالإنجليزية في كل اللغات، وذلك عن قصد. فهي معرّفات يحددها المعيار لا نثر — فـ U+200D اسمه ZERO WIDTH JOINER في العالم كله، وترجمته كانت ستجعل البحث عنه متعذرًا.
الترميزات والهروب
النقطة الرمزية عدد؛ ولا تصير بايتات إلا متى اختير ترميز. ويستعمل UTF-8 من بايت إلى أربعة ويترك ASCII كما هو، ولهذا انتصر. ويستعمل UTF-16 وحدة أو وحدتين من 16 بت، ومنه تتألف سلاسل JavaScript — ولذلك يبلّغ .length عن 2 لإيموجي واحد.
U+0041 41 # UTF-8: بايت واحد، كما في ASCII U+00E9 C3 A9 # UTF-8: بايتان U+20AC E2 82 AC # UTF-8: ثلاثة بايتات U+1F600 F0 9F 98 80 # UTF-8: أربعة بايتات
وكل سطر هنا يعطي أيضًا المحرف مكتوبًا هروبًا في JavaScript و‑JSON و‑HTML و‑CSS وعناوين URL و‑Python، جاهزًا للنسخ. وهي ليست متماثلة كلها، والفرق مهم فوق الـ BMP: فلدى JavaScript و‑Python هروب بالنقطة الرمزية ويستعملانه، بينما لا هروب كهذا لدى JSON فيلزمه تهجئة الإيموجي بنصفيه البديلين.
الأسئلة الشائعة
- لماذا سلسلتي أطول من عدد المحارف التي أراها؟
- إما أنها تحوي محارف خفية، وإما أنها تحوي حروفًا مرئية مبنية من عدة نقاط رمزية. وكلاهما معروض هنا: فالمحارف الخفية يُؤشَّر عليها، والحروف المرئية متعددة النقاط الرمزية تُجمَّع لترى المحرف الواحد والقيم المتعددة التي يتألف منها.
- سلسلتان تبدوان متطابقتين وليستا متساويتين. لماذا؟
- التسوية عادةً. فالحرف المشكول قد يكون نقطة رمزية واحدة أو حرفًا مع علامة ملحقة، وكلاهما يُرسم متماثلًا. الصق كل سلسلة هنا وقارن قوائم النقاط الرمزية، أو انظر أي صيغ تسوية تختلف عن المدخل.
- ما المسافة معدومة العرض وكيف دخلت نصي؟
- هي محرف بلا عرض وبلا أثر، يُستعمل للإيحاء بفرصة لكسر السطر. ويصل عادةً بنسخ نص من صفحة ويب أو من محرر مستندات أو من تطبيق محادثة، ولأن شيئًا لا يُعرض فإنه ينجو من كل مراجعة حتى يقارن شيء ما السلاسل فيفشل.
- ما الفرق بين النقطة الرمزية والمحرف؟
- النقطة الرمزية قيمة واحدة في يونيكود. أما المحرف بالمعنى المتداول فهو حرف مرئي، أي ما يعدّه القارئ واحدًا، وقد يتألف الحرف المرئي من عدة نقاط رمزية. فإيموجي العائلة خمس نقاط رمزية وحرف مرئي واحد.
- لماذا تقول الأداة إن بعض المحارف بلا اسم؟
- لأربعة أسباب مختلفة، وهي تقول أيها. فالبدائل ونقاط الاستعمال الخاص لا اسم لها في المعيار، وغير المسنَدة لا شيء فيها ليُسمّى، والمحرف من كتلة تاريخية نادرًا ما تُراجَع له اسم لا تحمله هذه النسخة: إذ يحتفظ جدول الأسماء بالكتل التي يلصق منها الناس فعلًا بدل إرسالها جميعًا.
- هل تحذير اختلاط الكتابات دليل على هجوم؟
- لا. إنه يعني أن كلمة واحدة تستمد حروفها من أكثر من نظام كتابة، وهي هيئة الاسم المنتحَل وهي كذلك أمر يفعله النص العادي أحيانًا. فهو داعٍ إلى النظر، لا حكم.
- هل يُرسَل شيء مما ألصقه إلى خادوم؟
- لا. تُنزَّل قاعدة بيانات المحارف مع الصفحة ويجري كل شيء في متصفحك؛ ولا يُرفَع شيء مما تكتبه ولا يُسجَّل، وهي تعمل بلا اتصال بالشبكة.