Emoji Detection in Text Strings: Algorithms and Libraries

Emoji Detection in Text Strings

Detecting whether a string contains emojis—and extracting them accurately—is harder than it looks. The Unicode standard has grown to include over 3,700 emoji characters spread across multiple code point ranges, with new ones added every year. A naive approach using a fixed range check will miss most of them.

This guide covers the algorithms, Unicode properties, and production-ready libraries you need to detect emojis reliably.

Why Simple Range Checks Fail

A common first attempt is checking whether a code point falls in the range U+1F600–U+1F64F (Emoticons block). This catches classics like 😀, 😂, and 😎, but misses:

  • Basic emoji: ©️ (U+00A9), ® (U+00AE), ™️ (U+2122) — in the Latin Extended range
  • Dingbats: ✅ (U+2705), ❌ (U+274C) — in the Dingbats block
  • Enclosed alphanumerics: 🅰️, 🅱️
  • ZWJZero Width Joiner (ZWJ)
    อักขระ Unicode ที่มองไม่เห็น (U+200D) ใช้เพื่อเชื่อมอิโมจิหลายตัวเข้าเป็นอิโมจิรวม เช่น การรวมคนและวัตถุเป็นอิโมจิอาชีพ
    sequences
    : 👨‍💻 (man technologist) — multiple code points joined by U+200D
  • Keycap sequences: 1️⃣ — digit + variation selectorVariation Selector (VS)
    อักขระ Unicode (VS-15 U+FE0E และ VS-16 U+FE0F) ที่กำหนดว่าอักขระจะแสดงผลเป็นข้อความ (สีเดียว) หรืออิโมจิ (มีสี)
    + combining enclosing keycap
  • Flag sequences: 🇺🇸 — pairs of Regional IndicatorRegional Indicator (RI)
    ตัวอักษร Unicode คู่ (U+1F1E6 ถึง U+1F1FF) ที่เมื่อรวมกันตามรหัส ISO 3166-1 alpha-2 จะสร้างอิโมจิธงชาติ
    letters

The only reliable approach is to use the official Unicode emoji property data.

The Unicode Emoji Properties Approach

Unicode defines several properties relevant to emoji detection, published in emoji-data.txt from the Unicode Character Database (UCD):

Property Meaning
Emoji The code point is an emoji
Emoji_Presentation Displayed as emoji by default (not text)
Emoji_Modifier A skin tone modifier (🏻–🏿)
Emoji_Modifier_Base Can be modified by a skin tone modifier
Emoji_Component Used in emoji sequences (ZWJ, keycap, etc.)
Extended_Pictographic Broader set including reserved ranges

For most detection tasks you want Extended_Pictographic, which includes current emoji plus code points reserved for future emoji assignments.

Detection in Python

Using the emoji Library

The emoji library maintains an up-to-date Unicode dataset:

import emoji

text = "Hello 👋 world! Check this out 🚀"

# Check if string contains any emoji
has_emoji = emoji.emoji_count(text) > 0
print(has_emoji)  # True

# Count emojis
count = emoji.emoji_count(text)
print(count)  # 2

# Extract emoji with positions
for item in emoji.emoji_list(text):
    print(item)
# {'match_start': 6, 'match_end': 7, 'emoji': '👋'}
# {'match_start': 26, 'match_end': 27, 'emoji': '🚀'}

# Replace emojis
clean = emoji.replace_emoji(text, replace="")
print(clean)  # "Hello  world! Check this out "

Using the regex Module with Unicode Properties

The third-party regex module (not the built-in re) supports Unicode properties:

import regex

# Match any Extended_Pictographic character or emoji sequence
EMOJI_PATTERN = regex.compile(
    r'\p{Extended_Pictographic}'
    r'(?:\uFE0F)?'           # optional variation selector-16
    r'(?:\u20E3)?'           # optional combining enclosing keycap
    r'(?:\uFE0F\u20E3)?'     # keycap sequence
    r'(?:\u200D\p{Extended_Pictographic}(?:\uFE0F)?)*'  # ZWJ sequences
    r'(?:[\U0001F1E0-\U0001F1FF]{2})?',  # flag sequences
    regex.UNICODE
)

text = "Deploying 🚀 to production 👨‍💻 — fingers crossed 🤞🏽"
matches = EMOJI_PATTERN.findall(text)
print(matches)  # ['🚀', '👨‍💻', '🤞🏽']

Pure stdlib with unicodedata

For simpler cases without extra dependencies, check the unicodedata category:

import unicodedata

def contains_emoji_simple(text: str) -> bool:
    for char in text:
        cat = unicodedata.category(char)
        # So (Symbol, other) covers many but not all emoji
        if cat == "So":
            return True
    return False

This is fast but incomplete — it misses many emoji that fall in other categories.

Detection in JavaScript

Using the emoji-regex Package

import emojiRegex from 'emoji-regex';

const regex = emojiRegex();
const text = "Meeting at 3pm 📅 — bring your laptop 💻";

// Test for presence
console.log(regex.test(text)); // true

// Extract all emojis
const matches = [...text.matchAll(regex)];
matches.forEach(m => {
  console.log(`Found: ${m[0]} at index ${m.index}`);
});
// Found: 📅 at index 15
// Found: 💻 at index 38

// Count
const count = [...text.matchAll(regex)].length;
console.log(count); // 2

Note that emoji-regex is generated directly from Unicode data, so it stays accurate across emoji versions.

Native Unicode Property Escapes (ES2018+)

Modern JavaScript engines support \p{} in regex with the u flag:

// Requires Node.js 10+ or modern browsers
const emojiRx = /\p{Emoji}/u;
const extPictoRx = /\p{Extended_Pictographic}/u;

console.log(emojiRx.test("Hello 🌍")); // true
console.log(extPictoRx.test("No emoji here")); // false

// Extract using matchAll
const text = "Status: ✅ Build passed, 🔴 Tests failed";
const allEmoji = [...text.matchAll(/\p{Extended_Pictographic}/gu)];
console.log(allEmoji.map(m => m[0])); // ['✅', '🔴']

Detection in Go

package main

import (
    "fmt"
    "unicode"
    "golang.org/x/text/unicode/rangetable"
)

// Basic check using unicode.Is
func containsEmoji(s string) bool {
    for _, r := range s {
        if unicode.Is(unicode.So, r) || // Symbol, other
           (r >= 0x1F600 && r <= 0x1FFFF) || // Supplemental symbols
           (r >= 0x2600 && r <= 0x27BF) {    // Misc symbols
            return true
        }
    }
    return false
}

func main() {
    texts := []string{
        "Hello world",
        "Rocket 🚀 launched",
        "©️ Copyright symbol",
    }
    for _, t := range texts {
        fmt.Printf("%q → %v\n", t, containsEmoji(t))
    }
}

For production Go code, consider the github.com/rivo/uniseg package, which handles grapheme cluster segmentation correctly and can identify emoji clusters.

Handling Edge Cases

Variation Selectors

Many emoji have both a text (VS15, U+FE0E) and emoji (VS16, U+FE0F) presentation. The digit ☎ can appear as ☎︎ (text) or ☎️ (emoji). Your detection should account for the variation selector:

phone_text = "\u260E\uFE0E"   # ☎︎  text presentation
phone_emoji = "\u260E\uFE0F"  # ☎️  emoji presentation

import emoji
print(emoji.emoji_count(phone_text))   # 0
print(emoji.emoji_count(phone_emoji))  # 1

ZWJ Sequences

👨‍💻 is a single grapheme cluster composed of 👨 + ZWJ (U+200D) + 💻. When counting or extracting emoji, treat ZWJ sequences as one unit. Libraries like emoji (Python) and emoji-regex (JS) handle this automatically.

Regional Indicator Flags

Country flags like 🇩🇪 consist of two Regional Indicator letters (U+1F1E6–U+1F1FF). They are only valid in pairs. A single 🇩 without a following 🇪 is not a flag.

Performance Considerations

For high-throughput text processing:

  1. Pre-compile your regex — do it once at module load, not per call
  2. Short-circuit on ASCII — if all bytes are < 128, there are no emoji (they are all non-ASCII)
  3. Use a library — regex-based approaches with proper Unicode support are faster than custom range tables you maintain yourself
def fast_has_emoji(text: str) -> bool:
    # Short-circuit: emoji require non-ASCII bytes in UTF-8UTF-8
การเข้ารหัส Unicode แบบความกว้างผันแปร ใช้ 1 ถึง 4 ไบต์ต่ออักขระ เป็นมาตรฐานหลักบนเว็บ (ใช้โดยเว็บไซต์กว่า 98%)
if text.isascii(): return False return emoji.emoji_count(text) > 0

Explore More on EmojiFYI

เครื่องมือที่เกี่ยวข้อง

🔍 ตัววิเคราะห์ลำดับ ตัววิเคราะห์ลำดับ
ถอดรหัสลำดับ ZWJ, ตัวปรับแต่งสีผิว, ลำดับ keycap และคู่ธงเป็นส่วนประกอบแต่ละชิ้น

คำในอภิธานศัพท์

Regional Indicator (RI) Regional Indicator (RI)
ตัวอักษร Unicode คู่ (U+1F1E6 ถึง U+1F1FF) ที่เมื่อรวมกันตามรหัส ISO 3166-1 alpha-2 จะสร้างอิโมจิธงชาติ
UTF-8 UTF-8
การเข้ารหัส Unicode แบบความกว้างผันแปร ใช้ 1 ถึง 4 ไบต์ต่ออักขระ เป็นมาตรฐานหลักบนเว็บ (ใช้โดยเว็บไซต์กว่า 98%)
Variation Selector (VS) Variation Selector (VS)
อักขระ Unicode (VS-15 U+FE0E และ VS-16 U+FE0F) ที่กำหนดว่าอักขระจะแสดงผลเป็นข้อความ (สีเดียว) หรืออิโมจิ (มีสี)
Zero Width Joiner (ZWJ) Zero Width Joiner (ZWJ)
อักขระ Unicode ที่มองไม่เห็น (U+200D) ใช้เพื่อเชื่อมอิโมจิหลายตัวเข้าเป็นอิโมจิรวม เช่น การรวมคนและวัตถุเป็นอิโมจิอาชีพ
กราฟีมคลัสเตอร์ กราฟีมคลัสเตอร์
อักขระที่ผู้ใช้มองเห็นเป็นหน่วยเดียว ซึ่งอาจประกอบด้วยโค้ดพอยท์ Unicode หลายตัวที่แสดงผลรวมกันเป็นหน่วยภาพเดียว
การแสดงผลแบบข้อความ การแสดงผลแบบข้อความ
การแสดงผลอักขระเป็นสัญลักษณ์ข้อความสีเดียว ไม่ว่าจะเป็นค่าเริ่มต้นหรือเมื่อใช้ Variation Selector-15
การแสดงผลแบบอิโมจิ การแสดงผลแบบอิโมจิ
การแสดงผลค่าเริ่มต้นของอักขระเป็นกลิฟอิโมจิสี ไม่ว่าจะโดยธรรมชาติหรือเมื่อถูกกระตุ้นด้วย Variation Selector-16
คีย์แคปซีเควนซ์ คีย์แคปซีเควนซ์
ลำดับอิโมจิที่ประกอบด้วยตัวเลขหรือสัญลักษณ์ ตามด้วย VS-16 (U+FE0F) และอักขระ keycap ล้อมรอบ (U+20E3)
โค้ดพอยท์ โค้ดพอยท์
ค่าตัวเลขเฉพาะที่กำหนดให้กับอักขระแต่ละตัวในมาตรฐาน Unicode เขียนในรูปแบบ U+XXXX (เช่น U+1F600 สำหรับ 😀)
ตัวปรับโทนผิว ตัวปรับโทนผิว
อักขระตัวปรับแต่ง Unicode ห้าตัวที่อิงตามสเกล Fitzpatrick ใช้เปลี่ยนสีผิวของอิโมจิมนุษย์ (U+1F3FB ถึง U+1F3FF)
มาตรฐาน Unicode มาตรฐาน Unicode
ระบบเข้ารหัสอักขระฉบับสมบูรณ์ที่ดูแลโดย Unicode Consortium กำหนดอักขระ คุณสมบัติ อัลกอริทึม และรูปแบบการเข้ารหัส
ยูนิโค้ด ยูนิโค้ด
มาตรฐานการเข้ารหัสอักขระสากลที่กำหนดหมายเลขเฉพาะให้กับอักขระทุกตัวในทุกระบบการเขียนและชุดสัญลักษณ์ รวมถึงอิโมจิ
อิโมจิ อิโมจิ
คำภาษาญี่ปุ่น (絵文字) แปลว่า 'อักขระภาพ' — สัญลักษณ์กราฟิกขนาดเล็กที่ใช้ในการสื่อสารดิจิทัลเพื่อแสดงความคิด อารมณ์ และวัตถุ
อิโมจิซีเควนซ์ อิโมจิซีเควนซ์
ชุดโค้ดพอยท์ Unicode ที่เรียงลำดับตั้งแต่หนึ่งตัวขึ้นไป ซึ่งรวมกันแล้วแสดงถึงอักขระอิโมจิหนึ่งตัว

บทความที่เกี่ยวข้อง