- 上一篇:
编码 - ASCII、Unicode(utf-8) -- 资料:
- Emoji Unicode Tables -
- 参考:
- ⭐️ 特殊字符(包括emoji)梳理和UTF8编码解码原理 -
- 千千秀字 - emoji(绘文字) - .html
- Emoji 识别与过滤 -
- 黎清海 - 简书
- 深入理解Emoji(一) —— 字符集,字符集编码 -
- 深入理解Emoji(二) —— 字节序和BOM -
- 深入理解Emoji(三) —— Emoji详解 -
- 相关:
- Emoji Frequency - /
识别和过滤 emoji 字符前,先来了解 emoji 字符。
像下面这种字符,是本文要讨论的 emoji (绘文字)字符:
😄😊😃😍😉
Emoji 绘文字(日语:絵文字/えもじ emoji)不是图片,每个emoji都像文字一样拥有独立编码并且可以存放于字库中,所以可以理解其为图形文字,实际使用中也是和文字一样的使用,可以复制粘贴和输入。
Emoji 是 Unicode 的一部分,它在 Unicode 中有对应的码点( CodePoint),也就是说,Emoji 符号就是一个 Unicode 字符。
常见的Emoji表情符号在Unicode字符集中的范围和具体的字节映射关系
可通过 Emoji Unicode Tables 查看到:
注:本篇文章在不同平台下观看效果会不一样
Unicode 组织的 Unicode® Emoji Charts v11.0 页面中可以找到完整的 Emoji 码点数据:
通过 脚本 getEmojiData.sh
处理 ,可以得到一个 完整的的码表
#! /bin/bash
cat "$1" | sed -n -e '/^#/d' -e '/^$/d' -e 's/[ ]*;.*$//p' | sort -u
$ ./getEmojiData. >
- emoji列表 - .html
在 Unicode 编码中,emoji主要安排在 1号平面第241行至第247行(1F000-1F6FF),以及 0号平面第39行和40行(2600-27FF)等位置
在 上一篇 文章提到,像 java、js 这些常用的编成语言是以 utf-16 来处理字符编码的。
于是,获取字符长度的时候,其实是根据 16位(2字节) 作为一个编码单元来分割字符串长度的。
于是,我们会看到下面的情况:(明明只有一个字符,长度却不为一的情况)
// javascript
"😀".length // 2
"🇨🇳".length // 4
"👩🏽🦳".length // 7
"👨👩👧👧".length // 11
可是,长度为 2 编码单元 可以理解为 码点 在 辅助平面 上,但 4、7、11 怎么理解?
这就涉及到Unicode的一个很重要的特性:组合字符
组合字符
Unicode 包含一个系统,可以合并多个编码点,动态组合字符。此系统用各种方式增加灵活性,而不引起编码点的巨大组合膨胀。
例如:
带重音的字符 “Á” 会被表示成由两个编码点组成的字符串:U+0041 “A” 拉丁大写字母 a 加上 U+0301 “◌́”组合尖音符号。这个字符串自动被渲染成单个字符:“Á”。
字位簇
如上所见,Unicode 包含多种情况,用户认为的一个“字符” 事实上底下可能由多个编码点组成。Unicode 使用「字位簇」的概念来表示这种情况。一个由一个或多个编码点组成的字符串构成一个 “用户感知的字符”。
UAX #29 为字位丛定义了精确的规则。
字位簇主要被用在文本编辑:
- 它们对光标和文本选择来说是最明显的单元;
- 使用字位簇,确保在复制和粘贴文本时不会突然丢掉一些符号;
- 同时左右方向键也总是以一个可见字符的距离移动;
- 等等
组合规则
现在,我们知道了一个Emoji表情可能由多个码点组成,这些码点都遵循着一定的规则来组合成不同的 Emoji 表情,我们来看下几种常见的规则:
单Unicode
最基本的Emoji表情,码点位于辅助平面上。在UTF-16下通过String.length()会被判断为2个长度,可以使用dePoints()通过码点数来获取正确的长度。
String.fromCodePoint(parseInt("1F600", 16))
// '😀'
双Unicode
最具代表性的就是旗帜序列(Flag Sequence),这类 Emoji 串是通过两个地域指示符(regional_indicator)组合的方式来表示一个国家的国旗。
总共有 26 个地域指示符(U+1F1E6
~ U+1F1FF
),每个指示符又对应于一个英文字母含义,例如 U+1F1E8 为地域指示符 C, U+1F1F3 为地域指示符 N。这些指示符两两组合表示一个国旗CN即中国国旗(🇨🇳)
在不支持Emoji5.0的系统上,会被显示为两个字母Emoji表情(🇨 🇳)。并不是 26 x 26 种组合是全部合法的,合法的 Flag Sequence 只有 256 种。
String.fromCodePoint(parseInt("1F1E8", 16), parseInt("1F1F3", 16))
// '🇨🇳'
变量选择器
在众多 Emoji 中, 有一些特殊的 Emoji 并没有显示的样式, 只是起到了控制的作用。这些控制型的 Emoji 与基础 Emoji 出现在一起, 可以展示更多的样式。比如 变量选择器:
<U+FE0E>
, 作用是让基础 Emoji 变成更接近文本样式 (text-style);<U+FE0F>
, 作用则是让基础 Emoji 变成更接近Emoji 样式 (emoji-style).VS-15 和 VS-16 加在基础 Emoji 字符的后面, 可以起到控制作用 (前提是必须系统支持, 否则会被忽略)。
String.fromCodePoint(parseInt("26A0", 16));
// '⚠'
'⚠'.length
// 1
String.fromCodePoint(parseInt("26A0", 16), parseInt("FE0E", 16)); // 更接近文本样式 (text-style)
// '⚠︎'
'⚠︎'.length
// 2
'⚠' == '⚠︎'
// false
String.fromCodePoint(parseInt("26A0", 16), parseInt("FE0F", 16)); // 更接近Emoji 样式 (emoji-style).
// '⚠️'
而在 VS-16 的基础上,还有一种 键帽序列 (KeyCap Sequence),这类 emoji 序列是将数字 (0-9)
,*
与 #
通过一个 U+20E3
字符转换为键帽的样式。由于这种样式要求必须以 emoji 风格展示,所有会在序列中添加样式限制 U+FE0F
。例如 U+0023 U+FE0F U+20E3
的 emoji 样式即是 #️⃣,U+0030 U+FE0F U+20E3
的 emoji 样式即是 0️⃣。其它与此类似。
String.fromCodePoint(parseInt("0023", 16));
// '#'
String.fromCodePoint(parseInt("0023", 16), parseInt("FE0F", 16));
// '#️'
String.fromCodePoint(parseInt("0023", 16), parseInt("FE0F", 16), parseInt("20E3", 16));
// '#️⃣'
另外, 还有一些控制型的 Emoji, 可以对人体肤色进行改变,改变对象仅限于 “表示人身体部位的Emoji”。
目前定义了五种修饰字符,分别表示颜色的由浅及深,它们分别是: U+1F3FB ~ U+1F3FF
(🏻…🏿) 共五个, 分别简称为:
例如,U+270D
(✍️) 就是一个可以被修饰的 emoji 字符,那么它被 U+1F3FF
修饰后就会变成 U+270D U+1F3FF
(✍️🏿)。
var colors = ['1F3FB', '1F3FC', '1F3FD', '1F3FE', '1F3FF']
for(var i=0; i<colors.length; i++) {var color = colors[i]var c = String.fromCodePoint(parseInt("270D", 16), parseInt(color, 16));console.log(c)
}
// ✍🏻
// ✍🏼
// ✍🏽
// ✍🏾
// ✍🏿
无缝连接序列
上面说到,通过一些特定的Emoji组合,可以结合出不同肤色的表情
性别,职业,等也可以结合
这种特殊不可见的排列方式被称为 “无缝连接” (“Zero-width joiner,即ZWJ”)
U+200D
便是连接这些表情的字符
例如:U+1F468 U+200D U+1F469 U+200D U+1F467
(👨👩👧) 这个 emoji 表示家庭即由三个emoji字符经 ZWJ 连接而成的:
U+1F468
(👨)U+1F469
(👩)U+1F467
(👧)当然不局限于家庭人物,包括职业,运动等许多都是用这种方式组成的
上述的 组合字符 提供非常便利的方案来快速的扩充 emoji 字符的丰富度。Emoji表情和ZWJ字符串不需要标准码协会批准就可以建立并在自有平台上使用 (不需要耗一个月甚至一年的时间等候审批,使表情开发变得更快)。即使在不支持ZWJ的老版本中,最多也是显示两个或是两个以上独立的表情,添加新的代码不会破坏其他或是出现丑陋的问号块。
标准码协会利用ZWJ字符序列的方式(可以跨多平台使用),使得各IT公司可以轻易地进行开发,不过同时也有个明显的问题。
苹果或是谷歌可以自主添加标志或解决问题,而不会影响与其他平台的兼容。这也使以ZWJ序列排列出的表现被跨平台支持,但事实上却没能被支持:
上述的问题导致了Emoji的混乱,这点其实跟Unicode的“统一”多多少少是有点冲突的。但不管怎么说,Emoji都是一个非常伟大且成功的发明。
识别 Emoji 问题在于划定其编码范围。但经过上面的描述我们知道,Emoji 的编码其实也是零散的(组合字符的使用导致任何一个普通字符都可能发展成 emoji 字符)
如何确定 Emoji 的编码范围?
可以查看官网给出的码点范围:/
相对应的,下面是识别 emoji 的 utf-16 编码正则表达式:
(u00a9|u00ae|[u2000-u3300]|ud83c[ud000-udfff]|ud83d[ud000-udfff]|ud83e[ud000-udfff])
/
本文发布于:2024-02-02 17:15:24,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170686532345267.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |