關于emoji,Go語言可以這么操作
什么是emoji
emoji就是一些意形符號。
emoji的實現(xiàn)
首先,你必須能夠區(qū)分unicode、utf8和字符之間的區(qū)別:
unicode,字符集,就是一個表格,記錄這字符和碼點(通常表示為U+0031)之間的關系utf8,是unicode的編碼方案之一(還有utf16、utf32等)字符,是人類可以閱讀的符號。emoji就是一批比較特殊的符號(可以理解為圖片或者像素點集合)
因為是一種實現(xiàn),所以不同平臺實現(xiàn)的各不一樣。以ok表情為例,各平臺的實現(xiàn)如下:

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在后面
func TestEmoji(t *testing.T) {
s := "1??"
fmt.Printf("字節(jié)數(shù):%d, 字符數(shù):%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,字節(jié)數(shù):%d\n", index, hex, utf8.RuneLen(item))
}
}
// 字節(jié)數(shù):7, 字符數(shù):3
// 字符串:1??
// ======================
// 序號0:Unicode 碼點:U+31,字節(jié)數(shù):1
// 序號1:Unicode 碼點:U+20e3,字節(jié)數(shù):3
// 序號2:Unicode 碼點:U+fe0f,字節(jié)數(shù):3
RGI_Emoji_Flag_Sequence
RGI(Recommended for General Interchange)表示可以在日常的交流中使用。
國家或地區(qū)縮寫字母編碼表: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
這里有三個比較特殊的地區(qū),分別是:英格蘭、蘇格蘭和威爾士。
英格蘭(????????????????????????):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 toneU+1F3FC:medium-light skin toneU+1F3FD:medium skin toneU+1F3FE:medium-dark skin toneU+1F3FF:dark skin tone
比如??的表情其實有5種膚色:

OK表情的5種膚色:https://www.notion.so/f557e5814e144e318b65251989d3afa6

零寬度鏈接符
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
字符串:???????????,占用字節(jié)數(shù):25, 字符數(shù):7
======================
序號0:Unicode 碼點:U+1f468,字節(jié)數(shù):4
序號1:Unicode 碼點:U+200d,字節(jié)數(shù):3
序號2:Unicode 碼點:U+1f469,字節(jié)數(shù):4
序號3:Unicode 碼點:U+200d,字節(jié)數(shù):3
序號4:Unicode 碼點:U+1f467,字節(jié)數(shù):4
序號5:Unicode 碼點:U+200d,字節(jié)數(shù):3
序號6:Unicode 碼點:U+1f466,字節(jié)數(shù):4
當然這樣的組合并不是無限的,所有合法的組合都可以在這里:https://www.unicode.org/Public/emoji/13.1/emoji-zwj-sequences.txt 找到。
emoji總結(jié)
emoji字符非固定長度,單個字符占用 3-4個字符,所以判斷是否是emoji表情,不能簡單通過長度判斷。
emoji長度不定:https://www.notion.so/d3090074f5444561b6e418b1967c96a3
emoji符號可以由一個或者多個字符組合而成,比如???????????是由7個字符組成,共占用25個字節(jié)。
go與emoji
https://github.com/go-xman/go.emoji
原理就是根據(jù)emoji兩個官方文檔 Emoji Sequence:https://www.unicode.org/Public/emoji/13.1/emoji-sequences.tx 和 Emoji ZWJ Sequence:https://www.unicode.org/Public/emoji/13.1/emoji-zwj-sequences.txt ,官方已經(jīng)將可以組合的emoji表情一一列舉出來了。
代碼實現(xiàn)就是將所有合法的序列全部導出成為一棵樹。當檢查字符串子串的時候,匹配樹中所代表的合法的子串就可以了。

func TestEmoji(t *testing.T) {
s := "????????????"
_ = emoji.ReplaceAllEmojiFunc(s, func(emoji string) string {
hexDump(emoji)
return ""
})
}
func hexDump(s string) {
fmt.Printf("字符串:%s,占用字節(jié)數(shù):%d, 字符數(shù):%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,字節(jié)數(shù):%d\n", index, hex, utf8.RuneLen(item))
}
}
=== RUN TestEmoji
字符串:????????,占用字節(jié)數(shù):18, 字符數(shù):5
======================
序號0:Unicode 碼點:U+1f469,字節(jié)數(shù):4
序號1:Unicode 碼點:U+200d,字節(jié)數(shù):3
序號2:Unicode 碼點:U+1f469,字節(jié)數(shù):4
序號3:Unicode 碼點:U+200d,字節(jié)數(shù):3
序號4:Unicode 碼點:U+1f466,字節(jié)數(shù):4
字符串:????,占用字節(jié)數(shù):8, 字符數(shù):2
======================
序號0:Unicode 碼點:U+1f1e8,字節(jié)數(shù):4
序號1:Unicode 碼點:U+1f1f3,字節(jié)數(shù):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
本文作者首發(fā)于 Go語言中文網(wǎng)網(wǎng)站,轉(zhuǎn)載請聯(lián)系授權
推薦閱讀
