关于emoji,go语言可以这么操作

nanjingfm · · 2951 次点击 · 开始浏览    置顶
这是一个创建于 的主题,其中的信息可能已经有所发展或是发生改变。

## 什么是emoji emoji就是一些意形符号。 ## emoji的实现 首先,你必须能够区分`unicode`、`utf8`和`字符`之间的区别: - `unicode`,字符集,就是一个表格,记录这字符和码点(通常表示为`U+0031`)之间的关系 - `utf8`,是unicode的编码方案之一(还有utf16、utf32等) - `字符`,是人类可以阅读的符号。emoji就是一批比较特殊的符号(可以理解为图片或者像素点集合) 因为是一种实现,所以不同平台实现的各不一样。以`ok`表情为例,各平台的实现如下: ![image-20210302223155359](https://bbk-images.oss-cn-shanghai.aliyuncs.com/typora/20210302223155.png) ## emoji分类 [参考](https://www.unicode.org/Public/emoji/13.1/emoji-sequences.txt) ### Basic_Emoji 基本emoji,包含两种类型 - 单一unicode字符 - 单一unicode字符后面增加`*U+FE0E*`或者`U+FE0F`分别表示以黑白文本模式还是彩色模式展示表情 [详情](https://www.unicode.org/Public/emoji/5.0/emoji-variation-sequences.txt) ### Emoji_Keycap_Sequence 键帽序列,都是`0-9、#、*`开头,然后后面紧跟着`U+FE0F`和`U+20E3`两个字符组合而成。 字符长度:`均是3字符` [键帽序列](https://www.notion.so/80b0da16e0304d7ea7653e7f3fff47c8) 需要注意的是苹果输入法打出的键帽序列是反的,即`U+20E3`在前`U+FE0F`在后面 ```go 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)表示可以在日常的交流中使用。 [国家或地区缩写字母编码表](https://www.notion.so/ea3653771b2f42a98c7a6d23a44aa94f) 如上表所示,`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` 他们是英国的组成国,具体请参考[这里](https://v.qq.com/x/page/q0313hm0d0t.html?winzoom=1) ### RGI_Emoji_Modifier_Sequence Unicode定义了5个用于emoji的肤色修饰字符,即特定的表情加上肤色修饰字符就会展示不同的颜色: - `U+1F3FB`:light skin tone - `U+1F3FC`:medium-light skin tone - `U+1F3FD`:medium skin tone - `U+1F3FE`:medium-dark skin tone - `U+1F3FF`:dark skin tone 比如👌的表情其实有5种肤色: ![image-20210302223211692](https://bbk-images.oss-cn-shanghai.aliyuncs.com/typora/20210302223211.png) [OK表情的5种肤色](https://www.notion.so/f557e5814e144e318b65251989d3afa6) ![image-20210302223222051](https://bbk-images.oss-cn-shanghai.aliyuncs.com/typora/20210302223222.png) ## 零宽度链接符 [ZWJ](https://www.unicode.org/Public/emoji/13.1/emoji-zwj-sequences.txt)即`Zero Width Joiner`,也就是零宽度链接符号。ZWJ的unicode代码为`U+200D`,因为是没有宽度的链接符,所以不可见,他的作用就是链接两个字符,比如“👨‍👩‍👧‍👦”就是由U+200D链接四个字符而成: [ZWJ示例](https://www.notion.so/2f8c4a839edd4abb8148baa90c174419) ```go 字符串:👨‍👩‍👧‍👦,占用字节数: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 ``` 当然这样的组合并不是无限的,所有合法的组合都可以在[这里](https://www.unicode.org/Public/emoji/13.1/emoji-zwj-sequences.txt)找到。 ## emoji总结 - emoji字符非固定长度,单个字符占用`3-4`个字符,所以判断是否是emoji表情,不能简单通过长度判断。 [emoji长度不定](https://www.notion.so/d3090074f5444561b6e418b1967c96a3) - emoji符号可以由一个或者多个字符组合而成,比如👨‍👩‍👧‍👦是由7个字符组成,共占用25个字节。 ## go与emoji [go-xman/go.emoji](https://github.com/go-xman/go.emoji) 原理就是根据emoji两个官方文档 [Emoji Sequence](https://www.unicode.org/Public/emoji/13.1/emoji-sequences.txt) 和 [Emoji ZWJ Sequence](https://www.unicode.org/Public/emoji/13.1/emoji-zwj-sequences.txt),官方已经将可以组合的emoji表情一一列举出来了。 代码实现就是将所有合法的序列全部`导出成为一棵树`。当检查字符串子串的时候,匹配树中所代表的合法的`子串`就可以了。 ![image-20210302223233235](https://bbk-images.oss-cn-shanghai.aliyuncs.com/typora/20210302223233.png) ```go 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 ``` ## 参考文献 - [Unicode](https://zh.wikipedia.org/wiki/Unicode) - [Unicode 颜文字(emoji)格式和 Go 代码处理](https://segmentfault.com/a/1190000022100299) - [About Emoji](https://home.unicode.org/emoji/about-emoji/) - [繪文字](https://zh.wikipedia.org/wiki/%E7%B9%AA%E6%96%87%E5%AD%97)

有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

2951 次点击  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传