डेवलपर्स के लिए इमोजी
इमोजी से जुड़े ज़्यादातर बग एक ही बेमेल से पैदा होते हैं: आपका कोड कुछ और गिनता है और पढ़ने वाले को कुछ और दिखता है। परिवार वाला इमोजी देखने में एक तस्वीर है, लेकिन उसमें सात code points, JavaScript के 11 कैरेक्टर और 25 बाइट होते हैं। हमने आम regex, segmenter और लंबाई जांचने के तरीकों को Unicode की अपनी सूची के सभी 3,963 इमोजी पर चलाया। यह पेज बताता है कि वे असल में क्या पकड़ते हैं, ताकि बग रिपोर्ट आपको यह बताए उससे पहले ही आप अपने काम के लिए सही तरीका चुन सकें।
एक इमोजी, हर भाषा में अलग लंबाई
हर सेल वह मान है जो वह expression अपने कॉलम के ऊपर दिए इमोजी के लिए लौटाता है। नतीजे चार समूहों में आते हैं: UTF-16 यूनिट, code points, UTF-8 बाइट और ग्रैफ़ीम (जिन्हें इंसान गिनता है)। ग्रैफ़ीम वाला कॉलम इस सर्वर पर Intl.Segmenter से निकाला गया है, इसलिए पुराने Unicode डेटा वाला runtime नए इमोजी के लिए ज़्यादा मान लौटा सकता है।
| Expression | क्या गिनता है | 😀 | ❤️ | 👍🏽 | 🇯🇵 | 👩💻 | 👨👩👧👦 | 🧑🏻❤️💋🧑🏼 |
|---|---|---|---|---|---|---|---|---|
JavaScripts.length | UTF-16 यूनिट | 2 | 2 | 4 | 4 | 5 | 11 | 15 |
JavaScript[...s].length | code points | 1 | 2 | 2 | 2 | 3 | 7 | 10 |
JavaScriptIntl.Segmenter | ग्रैफ़ीम | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
Pythonlen(s) | code points | 1 | 2 | 2 | 2 | 3 | 7 | 10 |
Pythonlen(s.encode('utf-8')) | UTF-8 बाइट | 4 | 6 | 8 | 8 | 11 | 25 | 35 |
Javas.length() | UTF-16 यूनिट | 2 | 2 | 4 | 4 | 5 | 11 | 15 |
Javas.codePointCount(0, s.length()) | code points | 1 | 2 | 2 | 2 | 3 | 7 | 10 |
C#s.Length | UTF-16 यूनिट | 2 | 2 | 4 | 4 | 5 | 11 | 15 |
C# (.NET 5+)new StringInfo(s).LengthInTextElements | ग्रैफ़ीम | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
Golen(s) | UTF-8 बाइट | 4 | 6 | 8 | 8 | 11 | 25 | 35 |
Goutf8.RuneCountInString(s) | code points | 1 | 2 | 2 | 2 | 3 | 7 | 10 |
Rusts.len() | UTF-8 बाइट | 4 | 6 | 8 | 8 | 11 | 25 | 35 |
Rusts.chars().count() | code points | 1 | 2 | 2 | 2 | 3 | 7 | 10 |
Swifts.count | ग्रैफ़ीम | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
Swifts.unicodeScalars.count | code points | 1 | 2 | 2 | 2 | 3 | 7 | 10 |
Rubys.length | code points | 1 | 2 | 2 | 2 | 3 | 7 | 10 |
Rubys.grapheme_clusters.length | ग्रैफ़ीम | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
PHPstrlen($s) | UTF-8 बाइट | 4 | 6 | 8 | 8 | 11 | 25 | 35 |
PHPmb_strlen($s) | code points | 1 | 2 | 2 | 2 | 3 | 7 | 10 |
PHPgrapheme_strlen($s) | ग्रैफ़ीम | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
MySQLCHAR_LENGTH(s) | code points | 1 | 2 | 2 | 2 | 3 | 7 | 10 |
MySQLLENGTH(s) | UTF-8 बाइट | 4 | 6 | 8 | 8 | 11 | 25 | 35 |
SQL ServerLEN(s) on nvarchar | UTF-16 यूनिट | 2 | 2 | 4 | 4 | 5 | 11 | 15 |
सीधा-सादा कट इमोजी के साथ क्या करता है
यहां परिवार वाले इमोजी 👨👩👧👦 पर हर n के लिए s.slice(0, n) लगाया गया है। ज़्यादातर कट ज़ोर से फ़ेल नहीं होते। वे एक अलग, छोटा परिवार लौटा देते हैं, और इसी वजह से इस तरह के बग बिना किसी की नज़र में आए प्रोडक्शन तक पहुंच जाते हैं।
| n पर कट | क्या बचता है | बचे हुए code points |
|---|---|---|
| s.slice(0, 1) | �आधा surrogate pair (� के रूप में दिखता है) | 0 |
| s.slice(0, 2) | 👨 | 1 |
| s.slice(0, 3) | 👨 | 2 |
| s.slice(0, 4) | 👨�आधा surrogate pair (� के रूप में दिखता है) | 2 |
| s.slice(0, 5) | 👨👩 | 3 |
| s.slice(0, 6) | 👨👩 | 4 |
| s.slice(0, 7) | 👨👩�आधा surrogate pair (� के रूप में दिखता है) | 4 |
| s.slice(0, 8) | 👨👩👧 | 5 |
| s.slice(0, 9) | 👨👩👧 | 6 |
| s.slice(0, 10) | 👨👩👧�आधा surrogate pair (� के रूप में दिखता है) | 6 |
| s.slice(0, 11) | 👨👩👧👦 | 7 |
झंडा जो देश बदल देता है
Regional indicator अक्षर स्ट्रिंग की शुरुआत से जोड़े बनाते हैं। 🇺🇸🇯🇵 की शुरुआत से एक code point हटाइए और बचे हुए अक्षर अलग तरह से जोड़े बना लेते हैं: 🇸🇯🇵। कोई एरर नहीं, बस एक अलग देश।
🇺🇸🇯🇵 US + JP → 🇸🇯 SJ (Svalbard & Jan Mayen) + 🇵
कौन सा इमोजी regex क्या पकड़ता है
2026-10-20 को सभी 3,963 fully-qualified इमोजी पर Node 25.2.1 में टेस्ट किया गया, जिसमें Unicode 17.0 का डेटा है। किसी पैटर्न को मैच तभी माना गया जब वह पूरे इमोजी को पकड़े।
| पैटर्न | मैच | क्या छूट जाता है |
|---|---|---|
| /^\p{RGI_Emoji}$/v | 3,944 / 3,963 | इंजन के Unicode डेटा से नया हर इमोजी: Emoji 18.0 (19) |
| Intl.Segmenter | 3,963 / 3,963 | इस runtime पर कुछ नहीं |
| /\p{Extended_Pictographic}/u | 3,692 / 3,963 | 259 झंडे और 12 keycaps, जिनमें कोई pictographic code point होता ही नहीं |
| /^\p{Extended_Pictographic}$/u | 1,193 / 3,963 | एक से ज़्यादा code point से बनी हर चीज़: स्किन टोन, झंडे, keycaps, ZWJ sequences और स्टाइल सेलेक्टर वाले इमोजी |
और जिससे बचना है: \p{Emoji} # * 0 1 2 3 4 5 6 7 8 9 © ® को भी पकड़ता है। इमोजी हटाने के लिए इसका इस्तेमाल करेंगे तो टेक्स्ट का हर अंक भी मिट जाएगा।
इमोजी हटाना: हर तरीका पीछे क्या छोड़ता है
नीचे की दोनों लाइनें एक ही टेक्स्ट से शुरू हुई थीं। बचे हुए कैरेक्टर ज़्यादातर फ़ॉन्ट में दिखते नहीं, और ठीक इसी वजह से वे बाद में दिक्कत करते हैं: सर्च में, डुप्लिकेट हटाने में और लंबाई की सीमा में।
Great 👍🏽 job ❤️ 👩💻 🇯🇵 #️⃣1
| तरीका | नतीजा | बचे हुए code points |
|---|---|---|
| \p{Extended_Pictographic} हटाएं | Great 🏽 job ️ 🇯🇵 #️⃣1 | U+1F3FD U+FE0F U+200D U+1F1EF U+1F1F5 U+FE0F U+20E3 |
| \p{RGI_Emoji} हटाएं | Great job 1 | कोई नहीं |
डेटाबेस में इमोजी कितनी जगह लेते हैं
सभी 3,963 इमोजी में हर इमोजी के UTF-8 बाइट। 30% चार बाइट या उससे कम में आ जाते हैं; सबसे लंबे को 35 चाहिए। अगर कोई कॉलम कैरेक्टर के बजाय बाइट में सीमित है, तो उसका साइज़ इस टेबल से तय करें, टेक्स्ट दिखने में कैसा है उससे नहीं।
| UTF-8 बाइट | जितने इमोजी आते हैं | हिस्सा |
|---|---|---|
| ≤ 4 | 1,193 | 30% |
| ≤ 8 | 2,346 | 59% |
| ≤ 11 | 2,424 | 61% |
| ≤ 17 | 3,424 | 86% |
| ≤ 28 | 3,868 | 98% |
| ≤ 35 | 3,963 | 100% |
🧑🏻❤️💋🧑🏼 U+1F9D1 U+1F3FB U+200D U+2764 U+FE0F U+200D U+1F48B U+200D U+1F9D1 U+1F3FC
वह गिनती चुनें जो आपकी लागू की गई सीमा से मेल खाए
कोई एक सही लंबाई नहीं होती, सिर्फ़ वह होती है जो आपके लागू किए जा रहे नियम से मेल खाए। बाइट में सीमित डेटाबेस कॉलम को UTF-8 बाइट चाहिए। जो टेक्स्ट फ़ील्ड किसी इंसान से 50 कैरेक्टर का वादा करता है उसे ग्रैफ़ीम चाहिए, वरना तीन झंडे टाइप करने वाले को बताया जाएगा कि उसने 12 इस्तेमाल किए। SQL Server अलग है: nvarchar(n) UTF-16 यूनिट गिनता है, इसलिए 😀 nvarchar के दो कैरेक्टर लेता है, लेकिन MySQL या PostgreSQL के varchar में एक, क्योंकि वे code points गिनते हैं। तय करें कि चारों में से आपका मतलब कौन सा है, उसे वेरिएबल के नाम में लिखें, बाकी अपने आप सही हो जाएगा।
ग्रैफ़ीम की सीमा पर काटें, इंडेक्स पर नहीं
इंडेक्स से किया गया कोई भी कट इमोजी के बीच में पड़ सकता है। UTF-16 में सबसे बुरा हाल आधा surrogate pair है, जिसे ज़्यादातर renderer सवालिया निशान वाले बॉक्स की तरह दिखाते हैं और कुछ JSON encoder सीधे ठुकरा देते हैं। code points पर कुछ भी दिखने में नहीं टूटता, जो और भी बुरा है: परिवार का एक बच्चा गायब हो जाता है, स्किन टोन अलग होकर भूरे चौकोर की तरह दिखता है, या झंडा दो अक्षर बन जाता है। हल यह है कि पहले segment करें और फिर पूरे ग्रैफ़ीम की गिनती पर काटें। अप्रैल 2024 में Firefox 125 के साथ आने के बाद से Intl.Segmenter हर बड़े ब्राउज़र में है, और Node में उससे भी पहले से, इसलिए हाथ से splitter लिखने का पुराना बहाना अब नहीं चलता।
कॉपी करने के लिए तैयार स्निपेट
छोटे, और जहां भाषा इजाज़त दे वहां बिना किसी dependency के। हर एक ऊपर की टेबल का एक केस हल करता है।
वह गिनें जो पढ़ने वाले को दिखता है (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;
}हर इमोजी ढूंढें, झंडे और keycaps समेत (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कोई भी regex कभी पूरा क्यों नहीं होता
regex इंजन की हर इमोजी property उस इंजन में compile किए गए Unicode डेटा से आती है, इसलिए कोई पैटर्न उतना ही नया होता है जितना उसे चलाने वाला runtime। हमारा अपना टेस्ट यही दिखाता है: \p{RGI_Emoji} ने 3,963 में से 3,944 पकड़े, क्योंकि 19 सबसे नए sequences अभी Node 25.2.1 की Unicode 17.0 टेबल में नहीं हैं। runtime अपग्रेड होने के बाद यही कोड उन्हें पकड़ लेगा, और पुराने ब्राउज़र वाले यूज़र के लिए वे छूटते रहेंगे। अगर किसी जांच को नए इमोजी पहले ही दिन से स्वीकार करने हैं, तो संरचना (Extended_Pictographic के साथ modifiers, joiners और selectors) या ग्रैफ़ीम के आधार पर मैच करें, और property का इस्तेमाल सिर्फ़ वहां करें जहां false negative से कोई नुकसान न हो।
एक ही इमोजी तीन तरह से सेव हो सकता है
Unicode में 3,963 fully-qualified इमोजी हैं, साथ में उन्हीं तस्वीरों के 1,029 minimally-qualified और 243 unqualified रूप, जो ज़्यादातर U+FE0F स्टाइल सेलेक्टर के बिना वाले वर्ज़न हैं। ❤ और ❤️ कई ऐप में एक जैसे दिखते हैं लेकिन अलग स्ट्रिंग हैं, इसलिए uniqueness जांच, रिएक्शन काउंट या सर्च इंडेक्स उन्हें दो अलग चीज़ें मानता है। Unicode normalization यहां मदद नहीं करता: NFC और NFKC variation selectors को नहीं छूते। अगर आप इमोजी की तुलना करते हैं या डुप्लिकेट हटाते हैं, तो एक रूप तय करें (fully-qualified सुरक्षित विकल्प है) और इनपुट पर qualified सूची के आधार पर बदलें, हर U+FE0F हटाने के बजाय, क्योंकि उससे 1️⃣ जैसे keycaps भी टूट जाएंगे।
इमोजी Unicode कन्वर्टरसभी ZWJ sequences, उनके साइज़ के साथइमोजी को सही गिनने वाला कैरेक्टर काउंटरइमोजी शब्दावली
इमोजी के बारे में डेवलपर्स के सवाल
JavaScript में एक इमोजी की लंबाई 2 क्यों होती है?
JavaScript स्ट्रिंग UTF-16 में होती हैं, और U+FFFF से ऊपर का हर कैरेक्टर दो 16-बिट यूनिट लेता है, जिसे surrogate pair कहते हैं। लगभग हर इमोजी U+FFFF से ऊपर है, इसलिए एक साधारण 😀 की .length भी 2 होती है। code points के लिए [...str].length और पढ़ने वाले को दिखने वाली गिनती के लिए Intl.Segmenter इस्तेमाल करें।
इमोजी मैच करने के लिए सबसे अच्छा regex कौन सा है?
आधुनिक JavaScript में /\p{RGI_Emoji}/v पूरे इमोजी sequences को झंडों और keycaps समेत पकड़ता है, लेकिन सिर्फ़ उस Unicode वर्ज़न तक जो इंजन जानता है। \p{Extended_Pictographic} झंडे और keycaps छोड़ देता है, और \p{Emoji} गलती से अंक, # और * भी पकड़ लेता है।
इमोजी को एक कैरेक्टर के रूप में कैसे गिनें?
ग्रैफ़ीम क्लस्टर गिनें। JavaScript में granularity grapheme के साथ Intl.Segmenter इस्तेमाल करें; Swift में String.count पहले से ऐसा करता है; Python में थर्ड-पार्टी regex मॉड्यूल का \X; PHP में intl एक्सटेंशन का grapheme_strlen।
एक इमोजी सेव करने के लिए कितने बाइट चाहिए?
UTF-8 में 3 से 35 बाइट तक। U+FFFF से ऊपर का एक code point वाला इमोजी 4 बाइट लेता है। स्किन टोन, झंडे और जुड़े हुए sequences जोड़ते जाते हैं: हमारे टेस्ट में सभी इमोजी में से 59% 8 बाइट में आ गए, और सबसे लंबा, दो स्किन टोन वाला kiss इमोजी, 35 बाइट लेता है।
डेटाबेस में मेरा इमोजी ???? क्यों बन जाता है?
कॉलम या कनेक्शन ऐसे character set का इस्तेमाल कर रहा है जो चार बाइट वाले कैरेक्टर नहीं रख सकता, आम तौर पर MySQL का पुराना utf8। टेबल और कनेक्शन दोनों को utf8mb4 पर बदलें। हमारा Unicode converter पेज सटीक ALTER TABLE स्टेटमेंट बताता है।
