Go,  技术,  编程语言

Emoji表情

Emoji表情 – 是开发中常遇到的一个难点,无论是存储还是识别,都有一定的难度,下面来具体介绍一下:

一、含义

Emoji表情

emoji 是可以插入文字的图形符号,是日语词“絵文字”(“えもじ”)的音译。

Emoji 在上个世纪90年代,由日本电信商引入服务,最早用于在短消息之中插入表情。2007年,苹果公司的 iPhone 支持了 Emoji,导致它在全世界范围的流行。目前全球约有90%的在线用户频繁使用emoji,每天有60亿个emoji表情符号被传送。

二、标准化

2010年10月发布的Unicode 6.0版首次收录emoji编码,从此,Emoji表情就是一个文字,不过会被渲染成图形而已。

Emoji 的国际标准在 2015 年出台,截止目前(2020-07),已经是v13.0版本了。

三、渲染实现

Unicode 只是规定了 Emoji 的码点和含义,但具体的实现与展示则依赖于其展示的系统,如果系统无法识别该Emoji表情,则无法正常显示。

同时,不同的系统,展示的方式同样有区别,同一个Emoji表情,在不同的系统上的展示可能不同。

四、表情存储

Emoji表情的mysql存储一直是开发中常遇到的情景,一般而言,常规的方案是采用utf8mb4编码方式进行存储。

如果业务上更改utf8mb4存储成本过大的话,也可以通过json_encode转为unicode编码,或者用varbinary类型进行储存。

五、表情的识别

emoji表情与其他字符的区分一直是个难点,如果想要知道一个字符串中有多少个Emoji表情,或者去除字符串中的Emoji表情等,都需要对Emoji表情进行识别。

一般而言,Emoji表情的识别有两种方案。

方案一:字节数

可以通过字节数来进行,毕竟大部分Emoji表情的字节数为4,可以跟其他字符区分开,如下

// 提取所含emoji表情字符数
func GetEmojiNum(text string) int {
	num := 0
	for _, value := range text {
		_, size := utf8.DecodeRuneInString(string(value))
		if size > 3 {
			num++
		}
	}
	return num
}

如果要求不是非常精确的话,这种方法完全可以满足我们的需求,但肯定会有一部分Emoji表情会被遗漏,因为很多Emoji表情的字节数并不是4。

方案二:编码范围匹配

如果想要精确的匹配出Emoji表情,就需要拿到所有Emoji表情的编码范围,然后通过正则进行匹配。

regex := "[\U0001f004]|[\U0001f0cf]|[\U0001f170-\U0001f171]|[\U0001f17e-\U0001f17f]|[\U0001f17f]|[\U0001f18e]|[\U0001f191-\U0001f19a]|[\U0001f201-\U0001f202]|[\U0001f21a]|[\U0001f22f]|[\U0001f232-\U0001f23a]|[\U0001f250-\U0001f251]|[\U0001f300-\U0001f321]|[\U0001f324-\U0001f393]|[\U0001f396-\U0001f397]|[\U0001f399]|[\U0001f39a-\U0001f39b]|[\U0001f39e-\U0001f3f0]|[\U0001f3f3-\U0001f3f5]|[\U0001f3f7-\U0001f4fd]|[\U0001f4ff-\U0001f53d]|[\U0001f549-\U0001f54e]|[\U0001f550-\U0001f567]|[\U0001f56f-\U0001f570]|[\U0001f573-\U0001f57a]|[\U0001f587]|[\U0001f58a-\U0001f58d]|[\U0001f590]|[\U0001f595-\U0001f596]|[\U0001f5a4-\U0001f5a5]|[\U0001f5a8]|[\U0001f5b1-\U0001f5b2]|[\U0001f5bc]|[\U0001f5c2-\U0001f5c4]|[\U0001f5d1-\U0001f5d3]|[\U0001f5dc-\U0001f5de]|[\U0001f5e1]|[\U0001f5e3]|[\U0001f5e8]|[\U0001f5ef]|[\U0001f5f3]|[\U0001f5fa-\U0001f64f]|[\U0001f680-\U0001f6c5]|[\U0001f6cb-\U0001f6d2]|[\U0001f6d5-\U0001f6d7]|[\U0001f6e0-\U0001f6e5]|[\U0001f6e9]|[\U0001f6eb-\U0001f6ec]|[\U0001f6f0]|[\U0001f6f3-\U0001f6fc]|[\U0001f7e0-\U0001f93a]|[\U0001f93c-\U0001f945]|[\U0001f947-\U0001f978]|[\U0001f97a-\U0001f9cb]|[\U0001f9cd-\U0001fa74]|[\U0001fa78-\U0001fa86]|[\U0001fa90-\U0001faa8]|[\U0001fab0-\U0001fab6]|[\U0001fac0-\U0001fac2]|[\U0001fad0-\U0001fad6]|[\u00a9]|[\u00ae]||[\u203c]|[\u2049]|[\u2122]|[\u2139]|[\u2194-\u2199]|[\u21a9-\u21aa]|[\u231a-\u231b]|[\u2328]|[\u23cf]|[\u23e9]|[\u23ea-\u23f3]|[\u23f8-\u23fa]|[\u24c2]|[\u25aa-\u25ab]|[\u25b6]|[\u25c0]|[\u25fb-\u25fe]|[\u2600-\u2604]|[\u260e]|[\u2611]|[\u2614-\u2615]|[\u2618]|[\u261d]|[\u2620]|[\u2622-\u2623]|[\u2626]|[\u262a]|[\u262e-\u262f]|[\u2638-\u263a]|[\u2640]|[\u2642]|[\u2648-\u2653]|[\u265f-\u2660]|[\u2663]|[\u2665-\u2666]|[\u2668]|[\u267b]|[\u267e-\u267f]|[\u2692-\u2697]|[\u2699]|[\u269b-\u269c]|[\u26a0-\u26a1]|[\u26a7]|[\u26aa-\u26ab]|[\u26b0-\u26b1]|[\u26bd-\u26be]|[\u26c4-\u26c5]|[\u26c8]|[\u26ce-\u26cf]|[\u26d1]|[\u26d3-\u26d4]|[\u26e9-\u26ea]|[\u26f0-\u26f5]|[\u26f7-\u26fa]|[\u26fd]|[\u2702]|[\u2705]|[\u2708-\u270d]|[\u270f]|[\u2712]|[\u2714]|[\u2716]|[\u271d]|[\u2721]|[\u2728]|[\u2733-\u2734]|[\u2744]|[\u2747]|[\u274c]|[\u274e]|[\u2753-\u2755]|[\u2757]|[\u2763-\u2764]|[\u2795-\u2797]|[\u27a1]|[\u27b0]|[\u27bf]|[\u2934-\u2935]|[\u2b05-\u2b07]|[\u2b1b-\u2b1c]|[\u2b50]|[\u2b55]|[\u3030]|[\u303d]|[\u3297]|[\u3299]"

rCharacter := regexp.MustCompile(regex)
num := len(rCharacter.FindAllStringSubmatch(text,-1))

上面我们拿到了所有的Emoji表情,但实际的业务场景中,我们所认知的Emoji表情应该是所有的图形符号,而有些图形符号并不属于Emoji表情的范围,所以我们需要再加上这些图形符号的编码范围。

杂项符号及图形768个字符中有637是emoji;增补符号及图形82个字符中有80个是emoji;所有80个表情符号都是emoji;交通及地图符号103个字符中有92个是emoji;杂项符号256个字符中有80个是emoji;装饰符号192个字符中有33个是emoji。

下面是结合后的正则匹配:

// 提取所含emoji表情字符数
func GetEmojiNum(text string) int {
	regex := "[\U0001f004]|[\U0001f0cf]|[\U0001f170-\U0001f171]|[\U0001f17e-\U0001f17f]|[\U0001f17f]|[\U0001f18e]|[\U0001f191-\U0001f19a]|[\U0001f1e6-\U0001f1ff]{1,2}|[\U0001f201-\U0001f202]|[\U0001f21a]|[\U0001f22f]|[\U0001f232-\U0001f23a]|[\U0001f250-\U0001f251]|[\U0001f300-\U0001f64f]|[\U0001f680-\U0001f6ff]|[\U0001f7e0-\U0001fa74]|[\U0001fa78-\U0001fa86]|[\U0001fa90-\U0001faa8]|[\U0001fab0-\U0001fab6]|[\U0001fac0-\U0001fac2]|[\U0001fad0-\U0001fad6]|[\u00a9]|[\u00ae]|[\u203c]|[\u2049]|[\u2122]|[\u2139]|[\u2194-\u2199]|[\u21a9-\u21aa]|[\u231a-\u231b]|[\u2328]|[\u23cf]|[\u23e9]|[\u23ea-\u23f3]|[\u23f8-\u23fa]|[\u24c2]|[\u25aa-\u25ab]|[\u25b6]|[\u25c0]|[\u25fb-\u25fe]|[\u2600-\u26ff]|[\u2700-\u27bf]|[\u2934-\u2935]|[\u2b05-\u2b07]|[\u2b1b-\u2b1c]|[\u2b50]|[\u2b55]|[\u3030]|[\u303d]|[\u3297]|[\u3299]"
	rCharacter := regexp.MustCompile(regex)
	return len(rCharacter.FindAllStringSubmatch(text,-1))
}

当然,这种做法还是存在一定误差的,因为一些Emoji表情实际是由多个编码组合而成的,所以会出现,一个Emoji表情,但是别出来的表情数>1,但相对而言,精确度比之字节比较不在一个等级。

而且这种方法仅是在这种获取Emoji表情数,或者替换/提取Emoji表情等需要明确每一个Emoji表情的情景会出现上述不准确情况,如果你的业务需求仅仅是判断字符串中是否包含Emoji表情,上述方案则是完全没问题的。

六、参考链接

Full Emoji List

WikiEmoji


精品课程


guest

0 评论
内联反馈
查看所有评论