go语言:彻底掌握emoji
关键词:emoji、unicode、utf8、go、表情
什么是emoji
emoji就是一些意形符号。
emoji的实现
首先,你必须能够区分unicode
、utf8
和字符
之间的区别:
unicode
,字符集,就是一个表格,记录这字符和码点(通常表示为U+0031
)之间的关系utf8
,是unicode的编码方案之一(还有utf16、utf32等)字符
,是人类可以阅读的符号。emoji就是一批比较特殊的符号(可以理解为图片或者像素点集合)
因为是一种实现,所以不同平台实现的各不一样。以ok
表情为例,各平台的实现如下:
emoji分类
Basic_Emoji
基本emoji,包含两种类型
- 单一unicode字符
- 单一unicode字符后面增加
*U+FE0E*
或者U+FE0F
分别表示以黑白文本模式还是彩色模式展示表情
emoji-variation-sequences.txt)
Emoji_Keycap_Sequence
键帽序列,都是0-9、#、*
开头,然后后面紧跟着U+FE0F
和U+20E3
两个字符组合而成。
字符长度:均是3字符
需要注意的是苹果输入法打出的键帽序列是反的,即U+20E3
在前U+FE0F
在后面
func TestEmoji(t *testing.T) {
s := "1⃣️"
fmt.Printf("字节数:%d, 字符数:%d\n", len(s), len([]rune(s)))
hexDump(s)
}
func hexDump(s string) {
fmt.Printf("字符串:%s\n======================\n", s)
for index, item := range []rune(s) {
hex := strconv.FormatInt(int64(item), 16)
fmt.Printf("序号%d:Unicode 码点:U+%s,字节数:%d\n", index, hex, utf8.RuneLen(item))
}
}
// 字节数:7, 字符数:3
// 字符串:1⃣️
// ======================
// 序号0:Unicode 码点:U+31,字节数:1
// 序号1:Unicode 码点:U+20e3,字节数:3
// 序号2:Unicode 码点:U+fe0f,字节数:3
RGI_Emoji_Flag_Sequence
RGI(Recommended for General Interchange)表示可以在日常的交流中使用。
如上表所示,U+1F1E6 ~ U+1F1FF
,分表代表A ~ Z
共计26
个字符。
- 比如中国缩写是
CN
,所以对应的旗帜编码就是U+1F1E8(C) U+1F1F3(N)
- 比如美国缩写是
US
,所以对应的旗帜编码就是U+1F1FA(U) U+1F1F8(S)
RGI_Emoji_Tag_Sequence
这里有三个比较特殊的地区,分别是:英格兰
、苏格兰
和威尔士
。
英格兰(🏴):U+1F3F4 U+E0067 U+E0062 U+E0065 U+E006E U+E0067 U+E007F
苏格兰(🏴):U+1F3F4 U+E0067 U+E0062 U+E0073 U+E0063 U+E0074 U+E007F
威尔士(🏴):U+1F3F4 U+E0067 U+E0062 U+E0077 U+E006C U+E0073 U+E007F
他们是英国的组成国,具体请参考这里
RGI_Emoji_Modifier_Sequence
Unicode定义了5个用于emoji的肤色修饰字符,即特定的表情加上肤色修饰字符就会展示不同的颜色:
U+1F3FB
:light skin toneU+1F3FC
:medium-light skin toneU+1F3FD
:medium skin toneU+1F3FE
:medium-dark skin toneU+1F3FF
:dark skin tone
比如👌的表情其实有5种肤色:
零宽度链接符
ZWJ即Zero Width Joiner
,也就是零宽度链接符号。ZWJ的unicode代码为U+200D
,因为是没有宽度的链接符,所以不可见,他的作用就是链接两个字符,比如“👨👩👧👦”就是由U+200D链接四个字符而成:
字符串:👨👩👧👦,占用字节数:25, 字符数:7
======================
序号0:Unicode 码点:U+1f468,字节数:4
序号1:Unicode 码点:U+200d,字节数:3
序号2:Unicode 码点:U+1f469,字节数:4
序号3:Unicode 码点:U+200d,字节数:3
序号4:Unicode 码点:U+1f467,字节数:4
序号5:Unicode 码点:U+200d,字节数:3
序号6:Unicode 码点:U+1f466,字节数:4
当然这样的组合并不是无限的,所有合法的组合都可以在这里找到。
emoji总结
- emoji字符非固定长度,单个字符占用
3-4
个字符,所以判断是否是emoji表情,不能简单通过长度判断。
- emoji符号可以由一个或者多个字符组合而成,比如👨👩👧👦是由7个字符组成,共占用25个字节。
go与emoji
原理就是根据emoji两个官方文档 Emoji Sequence 和 Emoji ZWJ Sequence,官方已经将可以组合的emoji表情一一列举出来了。
代码实现就是将所有合法的序列全部导出成为一棵树
。当检查字符串子串的时候,匹配树中所代表的合法的子串
就可以了。
func TestEmoji(t *testing.T) {
s := "👩👩👦🇨🇳"
_ = emoji.ReplaceAllEmojiFunc(s, func(emoji string) string {
hexDump(emoji)
return ""
})
}
func hexDump(s string) {
fmt.Printf("字符串:%s,占用字节数:%d, 字符数:%d\n======================\n", s, len(s), len([]rune(s)))
for index, item := range []rune(s) {
hex := strconv.FormatInt(int64(item), 16)
fmt.Printf("序号%d:Unicode 码点:U+%s,字节数:%d\n", index, hex, utf8.RuneLen(item))
}
}
=== RUN TestEmoji
字符串:👩👩👦,占用字节数:18, 字符数:5
======================
序号0:Unicode 码点:U+1f469,字节数:4
序号1:Unicode 码点:U+200d,字节数:3
序号2:Unicode 码点:U+1f469,字节数:4
序号3:Unicode 码点:U+200d,字节数:3
序号4:Unicode 码点:U+1f466,字节数:4
字符串:🇨🇳,占用字节数:8, 字符数:2
======================
序号0:Unicode 码点:U+1f1e8,字节数:4
序号1:Unicode 码点:U+1f1f3,字节数:4
--- PASS: TestEmoji (0.00s)
PASS
参考文献
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: