emoji 编码规则介绍
简介
emoji 来源于日语中的 絵 (e) 文字 (moji)
,起源于 1999 年日本手机(也有说在1994年的寻呼机中已经在使用了)。当时手机制造商 DoCoMo 建议把 emoji 加入 unicode 标准,但因未被广泛使用而被拒绝。
后来 emoji 在日本开始流行,但不同手机商使用了不同的 emoji 集合,编码上也存在重叠。不同设备之间 emoji 的显示存在问题,而且这些 emoji 没有对应的 unicode 字符,传输上也带来挑战。
随着 emoji 表情越来越广泛使用,unicode 官方在2007年5月正式成立符号小组委员会,并在8月确定在 unicode 中对emoji进行编码
emoji 官方文档:
- emoji 官方文档
- Emoji FAQ
这里可以动态看到 twitter 上 emoji 使用的排名情况
twitter 上的流行emoji
目前累计使用前3的 emoji 表情是:????❤ ????
emoji 目前最新版本是 v13,大概有3000个左右,并还在不断增加,可在这里查看目前所有emoji列表,和最近新加的 emoji。
emoji 编码
我们目前最常用的 emoji 通常由一个 unicode 编码点组成,比如 ???? (Cat Face with Tears of Joy),对应编码 U+1F639,UTF16 编码为 3DD8 39DE。
目前主流的开发语言比如 java, objc 等都是使用 UTF-16 编码,通常来说一个 emoji 会占用 2 个字符(叫做代理对),因此对于包含了 emoji 的字符串,其字符长度并不等于渲染后的字符数,这在编码时通常需要特别处理。
那么是否所有 emoji 符号都是对应 2 个 UTF16 字符呢,答案是否定的。emoji 标准中存在多种编码方式,允许由多个 unicode 编码点组合成一个 emoji 表情,那么最多可以由多少个 unicode 组成一个 emoji ,又有哪些编码组合方式呢,下面将详细介绍
emoji presentation sequence (表示序列)
表示序列
用于编码一个字符用 text 还是 emoji 进行表示(展示)
从 emoji 字符的表示角度来看,unicode 字符可以分成下面几类
- 单纯的文本字符,不对应任何 emoji 表示
- 单纯的 emoji 字符,不对应任何的 text 表示
- 默认显示为 emoji,也可作为 text 显示
- 默认显示为 text,也可作为 emoji 显示
由于一些字符既可以作为 text 又可以作为 emoji 显示,那么当我们想要指定用哪种方式显示时,就需要用到 presentation sequence,这里类似 unicode 字符中的 variation selection,这里不展开了。
文本表示:
text_presentation_sequence := emoji_character text_presentation_selector
text_presentation_selector := \x{FE0E}
emoji 表示:
emoji_presentation_sequence := emoji_character emoji_presentation_selector
emoji_presentation_selector := \x{FE0F}
一句话概括
就是如果一个字符后面加上U+FE0E,那么他就作为文本显示;加上U+FE0F就作为 emoji 显示
示例
- text 表示的雪人 ⛄︎ 对应编码
\u26C4\ufe0e
- emoji 表示的雪人 ⛄ 对应编码
\u26C4
- 这里还有更多示例
这里可以查到所有的 emoji presentation sequence
emoji modifier sequence (修饰序列)
修饰序列由一个基础字符(base)和一个修饰字符(modifier)组成,主要用来修改 emoji 中人的肤色,
- 定义
emoji_modifier_sequence := emoji_modifier_base emoji_modifier
- 说明
- emoji_modifier_base 可以被 emoji_modifier 修饰的基础 emoji 字符
- emoji_modifier 用于修饰前面的 base 字符
示例
这个文档定义了几种不同的肤色标准
Code | CLDR Short Name | Unicode Character Name |
---|---|---|
U+1F3FB | light skin tone | EMOJI MODIFIER FITZPATRICK TYPE-1-2 |
U+1F3FC | medium-light skin tone | EMOJI MODIFIER FITZPATRICK TYPE-3 |
U+1F3FD | medium skin tone EMOJI | MODIFIER FITZPATRICK TYPE-4 |
U+1F3FE | medium-dark skin tone | EMOJI MODIFIER FITZPATRICK TYPE-5 |
U+1F3FF | dark skin tone | EMOJI MODIFIER FITZPATRICK TYPE-6 |
- ???? 是一个emoji_modifier_base字符(\ud83e\uddd1)
- ???? 加上U+1F3FE字符后,就可以成生????????字符(\ud83e\uddd1\uD83C\uDFFE)
这里查看所有的emoji_modifier_base 字符
这里查看modifier的更多示例
emoji flag sequence (旗帜序列)
使用两位的地区码用于显示一个国旗(也可能看到就是两个英文字符)
定义:
emoji_flag_sequence := regional_indicator regional_indicator
regional_indicator 是一组对应a-z字母的unicode编码点,2个regional_indicator对应了2个字母组成的国家码,比如我们熟悉的CN、US、UK等。
示例:
- U+1F1E8 对应字母
C
(REGIONAL INDICATOR SYMBOL LETTER C) - U+1F1F3 对应字母
N
(REGIONAL INDICATOR SYMBOL LETTER N) - 以上两个字母组合起来就是字符 <????????>(\uD83C\uDDE8\uD83C\uDDF3)
注意:一些系统上以上字符会显示中国国旗,一些会显示CN
两个字母(比如我的visual code)
emoji keycap sequence (键盘序列)
这个很简单,就是 0-9#* 这几个字符加上 \x{FE0F 20E3},有点类似前面的 emoji presentation sequence,只是编码方式不一样。
emoji_keycap_sequence := [0-9#*] \x{FE0F 20E3}
示例:
-
2
的编码是 \u0032 - 加上 \uFE0F\u20e3 组成了 2️⃣(\u0032\uFE0F\u20e3)
- 你可以亲自到这里进行验证
在这里可以看到图片版本
emoji tag sequence (ETS)
tag sequence 可以认为是 modifier sequence 的一种扩展
- modifier sequence 只允许在 base 字符后跟一个 modifier 字符
- tag sequence 可以在 base 字符后跟多个 tag_spec 字符,最终使用 tag_end 标记结束
定义:
emoji_tag_sequence := tag_base tag_spec tag_end
tag_base := emoji_character
| emoji_modifier_sequence
| emoji_presentation_sequence
tag_spec := [\x{E0020}-\x{E007E}]+
tag_end := \x{E007F} (CANCEL TAG)
tag_base:单个emoji字符,或modifier序列、presentation序列
tag_spec:用于修饰前面的 emoji 字符,这里其实是映射了对应的ascii字符,这部分可以有多个字符组成
tag_end: 结束标志,由于 tag_spec 数量是不确定的,所以需要一个结束字符
示例:
这是官网的一个示例,使用 ETS 来表示一个国旗
通过 BLACK FLAG 加上地区码,再加上结束符来表示一个国旗
????gbeng✦
emoji zwj sequence (零宽连接序列, zwj=zero width joint)
简单说就是通过使用 ZWJ 字符(U+200D),对多个 emoji 表情进行组合。使用 ZWJ 有多种场景可以使用,比如改变基本 emoji 的方向,性别,职业等等。
emoji_zwj_sequence := emoji_zwj_element ( ZWJ emoji_zwj_element )+
ZWJ := \x{200d}
emoji_zwj_element :=
emoji_character
| emoji_presentation_sequence
| emoji_modifier_sequence
示例:
-
???????????????? 这个 emoji表面上看起来是一个 emoji。
但他其实是由 4 个 emoji 加上 3个 ZWJ 连接在一起的(1F468 200D 1F469 200D 1F467 200D 1F467) -
注意 ZWJ 是可以和前面的 modifier sequence 混用的,比如这个 ????????⚖️
更多的 ZWJ sequence 看这里
结语
- emoji 编码规则有很多,长度不固定,在处理断字、断行时需要特别小心。建议尽量使用系统库或ICU等第三方库进行处理。
- 每一种特殊的编码方法,可以单独写一条用例进行测试验证,这样保证不会出现严重错误