Unicode Emoji Properties: Extended_Pictographic, Emoji_Presentation, and More

Unicode Emoji Properties

Unicode assigns named properties to every code point, and emoji have a dedicated set defined in Unicode Standard Annex #51. These properties are the authoritative source for deciding whether a character is an emoji, how it should be displayed, and how it interacts with other characters.

Understanding these properties is essential for building correct emoji parsers, validators, and renderers.

The Six Core Emoji Properties

1. Emoji

The broadest property. A code point has Emoji=Yes if it can be used as an emoji. This includes characters that are also used as ordinary text symbols.

U+0023  # NUMBER SIGN          Emoji=Yes (part of # keycap)
U+00A9  © COPYRIGHT SIGN       Emoji=Yes
U+1F600 😀 GRINNING FACE       Emoji=Yes

About 1,400+ code points have Emoji=Yes. The Emoji property alone is too broad for most detection tasks because it includes digits, common punctuation, and symbols that usually appear as plain text.

2. Emoji_Presentation

A code point has Emoji_Presentation=Yes if it is displayed as a color emoji by default — without requiring a variation selector. This is the property most commonly used to answer "is this character normally shown as an emoji?"

U+1F600 😀  Emoji_Presentation=Yes  (emoji by default)
U+0023  #   Emoji_Presentation=No   (text by default, needs U+FE0F for emoji)
U+00A9  ©   Emoji_Presentation=No   (text by default)

Approximately 1,200 code points have Emoji_Presentation=Yes.

3. Emoji_Modifier

Marks the five skin tone modifier characters (Fitzpatrick scale):

Code Point Character Tone
U+1F3FB 🏻 Light
U+1F3FC 🏼 Medium-Light
U+1F3FD 🏽 Medium
U+1F3FE 🏾 Medium-Dark
U+1F3FF 🏿 Dark

These characters have no standalone appearance; they only make sense immediately following an Emoji_Modifier_Base character.

4. Emoji_Modifier_Base

A code point has Emoji_Modifier_Base=Yes if it can be followed by a skin tone modifier to create a modified sequence. Examples include 👋 (waving hand), 🖐 (hand with fingers splayed), and 🧑 (person).

# Checking modifier base + modifier sequence
base = "\U0001F44B"    # 👋
modifier = "\U0001F3FD"  # 🏽 Medium skin tone
combined = base + modifier
print(combined)  # 👋🏽

Not all person-like emoji are modifier bases. 👻 (ghost) and 🤖 (robot) are not modifier bases because they are not human-like enough.

5. Emoji_Component

A code point that can appear as part of an emoji sequence but is not itself an emoji when standalone. This includes:

  • Skin tone modifiers (U+1F3FB–U+1F3FF)
  • ZWJ零宽连接符(ZWJ) (ZWJ)
    一个不可见的Unicode字符(U+200D),用于将多个表情符号合并为单一复合表情符号,例如将人物与物体组合成职业表情符号。
    (U+200D)
  • Variation selectors (U+FE0E, U+FE0F)
  • Combining Enclosing Keycap (U+20E3)
  • Tag characters (U+E0020–U+E007F) used in subdivision flags
  • Regional Indicator letters (U+1F1E0–U+1F1FF)

Emoji_Component=Yes does not imply the character is itself an emoji — ZWJ is a joining control character, not an emoji.

6. Extended_Pictographic

The most useful property for comprehensive emoji detection. It covers:

  • All code points with Emoji_Presentation=Yes
  • Reserved code points in emoji blocks (for future emoji)
  • Additional pictographic symbols
Extended_Pictographic ⊃ Emoji_Presentation

Using Extended_Pictographic in a regex ensures your code will not break when new emoji are added to existing Unicode blocks, because those blocks are already reserved.

Accessing Property Data

From the Unicode Character Database

The official source is emoji-data.txt in the Unicode UCD:

# Download the latest data file
curl -O https://unicode.org/Public/UCD/latest/ucd/emoji/emoji-data.txt

# View Extended_Pictographic ranges
grep "Extended_Pictographic" emoji-data.txt | head -20

Sample output:

00A9          ; Emoji                # 1.1  [1] (©️)
00AE          ; Emoji                # 1.1  [1] (®️)
203C          ; Emoji                # 1.1  [1] (‼️)
...
1F600         ; Emoji                # 6.1  [1] (😀)
1F600         ; Emoji_Presentation   # 6.1  [1] (😀)
...
1F3FB..1F3FF  ; Emoji_Modifier       # 8.0  [5] (🏻..🏿)

Using Python's unicodedata Module

The standard library only exposes a subset of properties. For emoji properties, use the unicodedata2 or regex module:

import regex

def get_emoji_properties(char: str) -> dict:
    """Return relevant Unicode emoji properties for a character."""
    cp = ord(char)
    return {
        "code_point": f"U+{cp:04X}",
        "character": char,
        "is_emoji": bool(regex.match(r'\p{Emoji}', char)),
        "is_emoji_presentation": bool(regex.match(r'\p{Emoji_Presentation}', char)),
        "is_emoji_modifier": bool(regex.match(r'\p{Emoji_Modifier}', char)),
        "is_emoji_modifier_base": bool(regex.match(r'\p{Emoji_Modifier_Base}', char)),
        "is_emoji_component": bool(regex.match(r'\p{Emoji_Component}', char)),
        "is_extended_pictographic": bool(regex.match(r'\p{Extended_Pictographic}', char)),
    }

print(get_emoji_properties("👋"))
# {
#   'code_point': 'U+1F44B',
#   'character': '👋',
#   'is_emoji': True,
#   'is_emoji_presentation': True,
#   'is_emoji_modifier': False,
#   'is_emoji_modifier_base': True,
#   'is_emoji_component': False,
#   'is_extended_pictographic': True
# }

print(get_emoji_properties("🏽"))
# {
#   'code_point': 'U+1F3FD',
#   'is_emoji': True,
#   'is_emoji_modifier': True,
#   'is_emoji_component': True,
#   ...
# }

JavaScript with Unicode Property Escapes

ES2018 introduced \p{} escapes in regex (requires the u flag):

const tests = {
  emoji: /^\p{Emoji}$/u,
  emojiPresentation: /^\p{Emoji_Presentation}$/u,
  emojiModifier: /^\p{Emoji_Modifier}$/u,
  emojiModifierBase: /^\p{Emoji_Modifier_Base}$/u,
  emojiComponent: /^\p{Emoji_Component}$/u,
  extendedPictographic: /^\p{Extended_Pictographic}$/u,
};

function getProperties(char) {
  return Object.fromEntries(
    Object.entries(tests).map(([k, rx]) => [k, rx.test(char)])
  );
}

console.log(getProperties('🤝'));
// { emoji: true, emojiPresentation: true, emojiModifierBase: true,
//   emojiComponent: false, extendedPictographic: true, ... }

// Note: Emoji_Modifier_Base is NOT a standard \p{} escape in all engines
// Use a library for full coverage

Browser support for \p{Extended_Pictographic} is available in Chrome 64+, Firefox 78+, Safari 11.1+.

Practical Decision Guide

Use case Property to use
"Is this character typically shown as emoji?" Emoji_Presentation
"Should I include reserved future emoji ranges?" Extended_Pictographic
"Is this a skin tone modifier?" Emoji_Modifier
"Can I apply a skin tone to this?" Emoji_Modifier_Base
"Is this character part of a multi-code-point sequence?" Emoji_Component
"Is this character in the Unicode emoji set at all?" Emoji

Property Relationships

The properties form a hierarchy:

Extended_Pictographic
  ├── Emoji_Presentation  (subset of Extended_Pictographic)
  │     └── most "real" emoji
  └── Emoji               (broader, includes text-default symbols)
        ├── Emoji_Modifier_Base  (subset of Emoji)
        └── Emoji_Modifier       (subset of Emoji_Component)

Emoji_Component is orthogonal — ZWJ has Emoji_Component=Yes but Emoji=No.

Validating Emoji Sequences

Valid emoji sequences are defined in emoji-sequences.txt and emoji-zwj-sequences.txt in the UCD. A code point having Emoji=Yes does not mean any combination of emoji code points is valid:

import regex

# A minimal valid sequence checker
VALID_EMOJI = regex.compile(
    r'\p{Extended_Pictographic}\p{Emoji_Modifier}?'     # base + optional modifier
    r'(?:\uFE0F(?:\u20E3)?)?'                            # optional VS16 + keycap
    r'(?:\u200D\p{Extended_Pictographic}\p{Emoji_Modifier}?(?:\uFE0F)?)*'  # ZWJ chain
    r'|[\U0001F1E0-\U0001F1FF]{2}'                       # flag pair
)

for seq in ["👋🏽", "👨‍💻", "🇺🇸", "🏻👋"]:  # last one is invalid order
    match = VALID_EMOJI.fullmatch(seq)
    print(f"{seq}: {'valid' if match else 'invalid'}")

Explore More on EmojiFYI

相关工具

🔀 平台比较 平台比较
比较表情符号在 Apple、Google、Samsung、Microsoft 等平台上的渲染效果,并排查看视觉差异。
🔍 序列分析器 序列分析器
将 ZWJ 序列、肤色修饰符、键帽序列和旗帜对解析为独立组成部分。

术语表词条

Unicode标准 Unicode标准
由Unicode联盟维护的完整字符编码体系,定义字符、属性、算法和编码形式。
变体选择符 (VS) 变体选择符 (VS)
用于控制字符以文本形式(单色)还是表情符号形式(彩色)显示的Unicode字符。VS-15(U+FE0E)指定文本样式,VS-16(U+FE0F)指定表情符号样式。
地区标志符号 (RI) 地区标志符号 (RI)
成对使用时可组合成国旗表情符号的Unicode字符(U+1F1E6至U+1F1FF),依据ISO 3166-1 alpha-2代码对应各国国旗。
彩色表情符号 彩色表情符号
使用位图图像或彩色矢量图形渲染的全彩表情符号,与单色文本样式渲染相对。
码位 码位
Unicode标准中分配给每个字符的唯一数值,以U+XXXX格式表示(例如😀对应U+1F600)。
统一码 统一码
为所有书写系统和符号集(包括表情符号)中的每个字符分配唯一编号的通用字符编码标准。
肤色修饰符 肤色修饰符
基于菲茨帕特里克色度分级的五个Unicode修饰字符(U+1F3FB至U+1F3FF),用于改变人物表情符号的肤色。
表情符号(Emoji) 表情符号(Emoji)
来自日语「絵文字」(えもじ),意为「图画文字」,是用于数字通信中表达想法、情感和事物的小型图形符号。
表情符号序列 表情符号序列
由一个或多个Unicode码位按顺序组合,共同表示单个表情符号的字符集合。
零宽连接符(ZWJ) (ZWJ) 零宽连接符(ZWJ) (ZWJ)
一个不可见的Unicode字符(U+200D),用于将多个表情符号合并为单一复合表情符号,例如将人物与物体组合成职业表情符号。

相关故事