Skip to main content
Best Emojis

الإيموجي للمطورين

معظم أخطاء الإيموجي تنبع من تعارض واحد: الكود يعدّ شيئًا مختلفًا عمّا يراه القارئ. إيموجي العائلة صورة واحدة، لكنه سبع نقاط ترميز (code points) و11 حرفًا في JavaScript و25 بايت. شغّلنا التعابير النمطية والمقسِّمات وفحوص الطول الشائعة على جميع الإيموجي البالغ عددها 3,963 في قائمة Unicode الرسمية، وننشر في هذه الصفحة ما تطابقه فعلًا، لتختار الطريقة المناسبة لحالتك قبل أن يخبرك تقرير خطأ بالطريقة التي اخترتها.

3,963
إيموجي في Unicode 18.0، اختُبرت جميعها
2,770
تتكوّن من أكثر من نقطة ترميز
271
يُفلتها مرشّح Extended_Pictographic
35
بايت في أطول إيموجي

إيموجي واحد، وطول مختلف في كل لغة

كل خلية هي ما يُرجعه ذلك التعبير للإيموجي في رأس العمود. تنقسم النتائج إلى أربع فئات: وحدات UTF-16، ونقاط الترميز، وبايتات UTF-8، والوحدات الكتابية (graphemes، أي ما يعدّه الإنسان). يُحسب عمود الوحدات الكتابية بواسطة Intl.Segmenter على هذا الخادم، لذا قد تُرجع بيئة تشغيل ذات بيانات Unicode أقدم قيمًا أكبر لأحدث الإيموجي.

التعبيرما يعدّه😀❤️👍🏽🇯🇵👩‍💻👨‍👩‍👧‍👦🧑🏻‍❤️‍💋‍🧑🏼
JavaScripts.lengthوحدات UTF-16224451115
JavaScript[...s].lengthنقاط ترميز12223710
JavaScriptIntl.Segmenterوحدات كتابية1111111
Pythonlen(s)نقاط ترميز12223710
Pythonlen(s.encode('utf-8'))بايتات UTF-84688112535
Javas.length()وحدات UTF-16224451115
Javas.codePointCount(0, s.length())نقاط ترميز12223710
C#s.Lengthوحدات UTF-16224451115
C# (.NET 5+)new StringInfo(s).LengthInTextElementsوحدات كتابية1111111
Golen(s)بايتات UTF-84688112535
Goutf8.RuneCountInString(s)نقاط ترميز12223710
Rusts.len()بايتات UTF-84688112535
Rusts.chars().count()نقاط ترميز12223710
Swifts.countوحدات كتابية1111111
Swifts.unicodeScalars.countنقاط ترميز12223710
Rubys.lengthنقاط ترميز12223710
Rubys.grapheme_clusters.lengthوحدات كتابية1111111
PHPstrlen($s)بايتات UTF-84688112535
PHPmb_strlen($s)نقاط ترميز12223710
PHPgrapheme_strlen($s)وحدات كتابية1111111
MySQLCHAR_LENGTH(s)نقاط ترميز12223710
MySQLLENGTH(s)بايتات UTF-84688112535
SQL ServerLEN(s) on nvarcharوحدات UTF-16224451115

ما يفعله الاقتطاع الساذج بالإيموجي

هذه نتيجة تطبيق s.slice(0, n) على العائلة 👨‍👩‍👧‍👦 لكل قيمة من n. معظم عمليات القطع لا تفشل بشكل واضح، بل تُرجع عائلة مختلفة أصغر، وهكذا يصل هذا النوع من الأخطاء إلى بيئة الإنتاج دون أن يلاحظه أحد.

القطع عند nما يتبقىنقاط الترميز المتبقية
s.slice(0, 1)�نصف زوج بديل (يظهر بشكل �)0
s.slice(0, 2)👨1
s.slice(0, 3)👨‍2
s.slice(0, 4)👨‍�نصف زوج بديل (يظهر بشكل �)2
s.slice(0, 5)👨‍👩3
s.slice(0, 6)👨‍👩‍4
s.slice(0, 7)👨‍👩‍�نصف زوج بديل (يظهر بشكل �)4
s.slice(0, 8)👨‍👩‍👧5
s.slice(0, 9)👨‍👩‍👧‍6
s.slice(0, 10)👨‍👩‍👧‍�نصف زوج بديل (يظهر بشكل �)6
s.slice(0, 11)👨‍👩‍👧‍👦7

العلم الذي يغيّر الدولة

تتزاوج حروف المؤشرات الإقليمية بدءًا من أول السلسلة النصية. احذف نقطة ترميز واحدة من بداية 🇺🇸🇯🇵 فتتزاوج الحروف المتبقية بشكل مختلف: 🇸🇯🇵. لا خطأ، مجرد دولة أخرى.

🇺🇸🇯🇵 US + JP → 🇸🇯 SJ (Svalbard & Jan Mayen) + 🇵

أي تعبير نمطي للإيموجي يطابق ماذا

اختُبر بتاريخ 2026-10-20 على جميع الإيموجي fully-qualified البالغ عددها 3,963، باستخدام Node 25.2.1 الذي يتضمن بيانات Unicode 17.0. لا يُحتسب النمط مطابقًا إلا إذا طابق الإيموجي كاملًا.

النمطالمطابقاتما يُفلته
/^\p{RGI_Emoji}$/v3,944 / 3,963كل إيموجي أحدث من بيانات Unicode في المحرّك: Emoji 18.0 (19)
Intl.Segmenter3,963 / 3,963لا شيء على بيئة التشغيل هذه
/\p{Extended_Pictographic}/u3,692 / 3,963259 علمًا و12 من أزرار المفاتيح، لا تحتوي أي نقطة ترميز تصويرية على الإطلاق
/^\p{Extended_Pictographic}$/u1,193 / 3,963كل ما يتكوّن من أكثر من نقطة ترميز: درجات لون البشرة، والأعلام، وأزرار المفاتيح (keycaps)، وتسلسلات ZWJ، والإيموجي ذات محدد النمط

والنمط الذي يجب تجنّبه: \p{Emoji} يطابق أيضًا # * 0 1 2 3 4 5 6 7 8 9 © ®. إذا استخدمته لحذف الإيموجي فستحذف كل رقم في النص.

حذف الإيموجي: ما تتركه كل طريقة وراءها

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

Great 👍🏽 job ❤️ 👩‍💻 🇯🇵 #️⃣1

الطريقةالنتيجةنقاط الترميز المتبقية
حذف \p{Extended_Pictographic}Great 🏽 job ️ ‍ 🇯🇵 #️⃣1U+1F3FD U+FE0F U+200D U+1F1EF U+1F1F5 U+FE0F U+20E3
حذف \p{RGI_Emoji}Great job 1لا شيء

كم تشغل الإيموجي في قاعدة البيانات

عدد بايتات UTF-8 لكل إيموجي عبر جميع الإيموجي البالغ عددها 3,963. 30% منها تتسع في أربعة بايتات أو أقل؛ وأطولها يحتاج إلى 35. إذا كان العمود محدودًا بالبايتات لا بالأحرف، فحدّد حجمه بناءً على هذا الجدول، لا على شكل النص.

بايتات UTF-8الإيموجي التي تتسعالنسبة
≤ 41,19330%
≤ 82,34659%
≤ 112,42461%
≤ 173,42486%
≤ 283,86898%
≤ 353,963100%

🧑🏻‍❤️‍💋‍🧑🏼 U+1F9D1 U+1F3FB U+200D U+2764 U+FE0F U+200D U+1F48B U+200D U+1F9D1 U+1F3FC

اختر طريقة العدّ التي تطابق الحد الذي تفرضه

لا يوجد طول صحيح واحد، بل الطول الذي يطابق القاعدة التي تفرضها. عمود قاعدة البيانات المحدود بالبايتات يحتاج إلى بايتات UTF-8. وحقل النص الذي يعد المستخدم بخمسين حرفًا يحتاج إلى الوحدات الكتابية، وإلا فسيُقال لمن يكتب ثلاثة أعلام إنه استخدم 12 حرفًا. يشذّ SQL Server عن القاعدة: فـ nvarchar(n) يعدّ وحدات UTF-16، لذا يشغل 😀 حرفين من nvarchar لكنه يشغل حرفًا واحدًا من varchar في MySQL أو PostgreSQL، لأنهما يعدّان نقاط الترميز. حدّد أيّ الأربعة تقصد، واكتبه في اسم المتغير، وسيأتي الباقي تلقائيًا.

اقتطع عند حدود الوحدات الكتابية، لا عند الفهارس

أي قطع بالفهرس قد يقع في منتصف إيموجي. مع UTF-16 تكون أسوأ حالة نصف زوج بديل، تعرضه معظم محركات العرض كمربع بعلامة استفهام، وترفضه بعض مُرمِّزات JSON مباشرة. ومع نقاط الترميز لا ينكسر شيء ظاهريًا، وهذا أسوأ: تفقد العائلة طفلًا، أو تنفصل درجة لون البشرة وتظهر كمربع بني، أو يتحول العلم إلى حرفين. الحل هو التقسيم أولًا ثم قطع عدد صحيح من الوحدات الكتابية. أصبح Intl.Segmenter متاحًا في كل المتصفحات الرئيسية منذ أن أضافه Firefox 125 في أبريل 2024، وفي Node منذ مدة أطول، فلم يعد هناك مبرر لكتابة مقسِّم يدوي.

مقتطفات جاهزة للنسخ

قصيرة، ودون اعتماديات خارجية حيثما تسمح اللغة. كل واحدة تعالج حالة من الجداول أعلاه.

عدّ ما يراه القارئ (JavaScript)

const seg = new Intl.Segmenter(undefined, { granularity: 'grapheme' });
const visibleLength = (s) => [...seg.segment(s)].length;

visibleLength('👨‍👩‍👧‍👦 ok'); // 4, while '👨‍👩‍👧‍👦 ok'.length is 14

الاقتطاع دون تقسيم إيموجي (JavaScript)

function truncate(s, max, ellipsis = '…') {
  const parts = [...seg.segment(s)].map((x) => x.segment);
  return parts.length <= max ? s : parts.slice(0, max - 1).join('') + ellipsis;
}

العثور على كل الإيموجي، بما فيها الأعلام وأزرار المفاتيح (JavaScript)

// ES2024 'v' flag: Chrome 112, Safari 17, Firefox 116, Node 20
const emoji = /\p{RGI_Emoji}/gv;
'Go 🇯🇵 #️⃣1 👍🏽'.match(emoji); // ['🇯🇵', '#️⃣', '👍🏽']

الشيء نفسه في Python، باستخدام وحدة regex

import regex  # pip install regex; the built-in re has no \X

graphemes = regex.findall(r'\X', '👨‍👩‍👧‍👦 ok')
len(graphemes)  # 4, while len('👨‍👩‍👧‍👦 ok') is 10

أعمدة تقبل كل الإيموجي

-- MySQL: utf8mb4 on the column AND the connection
CREATE TABLE posts (body VARCHAR(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci);
SET NAMES utf8mb4;

-- PostgreSQL: any UTF8 database already stores every emoji
-- SQL Server: use nvarchar, and remember LEN() counts UTF-16 units

لماذا لا يكتمل أي تعبير نمطي أبدًا

كل خاصية إيموجي في محرّك التعابير النمطية تأتي من بيانات Unicode المضمّنة في ذلك المحرّك، لذا فالنمط لا يكون أحدث من بيئة التشغيل التي تنفّذه. اختبارنا يثبت ذلك: طابق \p{RGI_Emoji} 3,944 من أصل 3,963، لأن أحدث 19 تسلسلات ليست بعد في جداول Unicode 17.0 الخاصة بـ Node 25.2.1. الكود نفسه سيطابقها بعد ترقية بيئة التشغيل، بينما سيظل المستخدم على متصفح أقدم يُفلتها. إذا كان على الفحص قبول الإيموجي الجديدة منذ يوم صدورها، فطابق بالبنية (Extended_Pictographic مع المعدِّلات والوصلات والمحددات) أو بالوحدات الكتابية، ولا تستخدم الخاصية إلا حيث لا يضر السلبي الكاذب.

يمكن تخزين الإيموجي نفسه بثلاث طرق

تدرج Unicode 3,963 إيموجي fully-qualified، إضافة إلى 1,029 صيغة minimally-qualified و243 صيغة unqualified للصور نفسها، ومعظمها نسخ بلا محدد النمط U+FE0F. يبدو ❤ و❤️ متطابقين في كثير من التطبيقات لكنهما سلسلتان مختلفتان، لذا يعاملهما فحص التفرّد أو عدّاد التفاعلات أو فهرس البحث كشيئين منفصلين. ولا تساعد تسوية Unicode هنا: فـ NFC وNFKC لا تمسّان محددات التنويع. إذا كنت تقارن الإيموجي أو تزيل تكرارها، فاعتمد صيغة واحدة (fully-qualified هي الخيار الآمن) وحوّل المدخلات إليها باستخدام قائمة التأهيل، بدلًا من حذف كل U+FE0F، لأن ذلك سيكسر أيضًا أزرار المفاتيح مثل 1️⃣.

محوّل الإيموجي إلى Unicodeجميع تسلسلات ZWJ مع أحجامهاعدّاد أحرف يعدّ الإيموجي بشكل صحيحمسرد مصطلحات الإيموجي

أسئلة يطرحها المطورون عن الإيموجي

لماذا يكون طول الإيموجي 2 في JavaScript؟

سلاسل JavaScript مرمّزة بـ UTF-16، وأي حرف أعلى من U+FFFF يشغل وحدتين من 16 بت، أي زوجًا بديلًا. تقع معظم الإيموجي تقريبًا فوق U+FFFF، لذا حتى 😀 البسيط تكون قيمة .length له 2. استخدم [...str].length لعدّ نقاط الترميز، أو Intl.Segmenter لعدّ ما يراه القارئ.

ما أفضل تعبير نمطي لمطابقة الإيموجي؟

في JavaScript الحديثة، يطابق /\p{RGI_Emoji}/v تسلسلات الإيموجي الكاملة، بما فيها الأعلام وأزرار المفاتيح، لكن فقط حتى إصدار Unicode الذي يعرفه المحرّك. أما \p{Extended_Pictographic} فيُفلت الأعلام وأزرار المفاتيح، و\p{Emoji} يطابق خطأً الأرقام و# و*.

كيف أعدّ الإيموجي كحرف واحد؟

عُدّ عناقيد الوحدات الكتابية. في JavaScript استخدم Intl.Segmenter مع granularity grapheme؛ وفي Swift يفعل String.count ذلك أصلًا؛ وفي Python استخدم \X من وحدة regex الخارجية؛ وفي PHP استخدم grapheme_strlen من امتداد intl.

كم بايتًا أحتاج لتخزين إيموجي واحد؟

في UTF-8، بين 3 و35 بايت. الإيموجي ذو نقطة الترميز الواحدة فوق U+FFFF يشغل 4. درجات لون البشرة والأعلام والتسلسلات المتصلة تزيد الحجم: في اختبارنا اتسع 59% من جميع الإيموجي في 8 بايتات، وأطولها، وهو قبلة بدرجتين للون البشرة، يشغل 35.

لماذا يتحول الإيموجي إلى ???? في قاعدة البيانات؟

العمود أو الاتصال يستخدم مجموعة أحرف لا تستوعب الأحرف ذات الأربعة بايتات، وغالبًا ما تكون utf8 القديمة في MySQL. حوّل الجدول والاتصال معًا إلى utf8mb4. تشرح صفحة محوّل Unicode لدينا عبارة ALTER TABLE بالتفصيل.