如何转义emoji表情,让它可以存入utf8的数据库

1. Unicode是什么

Unicode(中文:万国码、国际码、统一码、单一码)是计算机科学领域里的一项业界标准。它对世界上大部分的文字系统进行了整理、编码,使得电脑可以用更为简单的方式来呈现和处理文字。

简单说来,就是把世界上所有语言的字,加上所有能找到的符号(如高音谱号、麻将、emoji)用同一套编码表示出来。

2. UTF-8是什么

UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码。可变长度的意思在于,如果能使用1字节编码,UTF-8绝对不会使用2字节去表示。举个例子,UTF-8的1字节部分和ASCII码是相同的。所以表示'A'这个字符的时候,UTF-8与ASCII码不仅编码相同,而且都是只使用1字节。

3. Character Set和Collation是什么

Character Set是一套符号以及编码。Collation是character set的排序方法。在中文版的MySQL中,character set被翻译为“字符集”,collation被翻译为“整理”。

举个例子,UTF-8是character set,utf8_unicode_ci和utf8mb4_unicode_ci就是collation。

Collation的作用主要有二:字符排序与查找字符。

字符排序的作用是显而易见的,不过还是要用几个例子加以说明。比如要比较a和b的大小,因为在26个英文字母里面,a在b前,所以在编码的时候,也把a放在b前面。这样就产生了第一种排序方式,通过字符编码的大小来排序。而在中文里面,“年”和“日”的排序,除了按照字符编码大小,还可以有另外一些标准。比如可以按照笔画序,“年”的第一笔是丿,“日”的第一笔是丨,而丨是排在丿前的,所以就将“日”排在前面;也可以按拼音序,“年”是n开头,“日”是r开头,于是把“年”排在前面。除此以外,还可以定义部首序、笔画数序等等,而不同的排序方法会有不同的结果。英文也有大小写敏感与不敏感的排序方式。种种不同的排序方式,就形成了不同的collations。

Collation的第二个作用则是查找字符是否在一个字符集里面。既然是一个有序的集合,则可以快速地通过一个编码值确定一个字符是否在集合内。这个特性是我们在不知不觉中使用的。比如使用中文输入法,就是通过输入法找到一个编码,通过collation把它查找出来的。

4. Unicode再深入:Plane和中日韩越统一表意文字

utf8_unicode_ci和utf8mb4_unicode_ci这两个collations都是基于UTF-8编码的,但排序方面或多或少会有差别。可是更大的差别是它查找字符的集合。这需要提到一个Unicode的概念:Plane。

4.1. Plane

Plane中文译作“Unicode平面字符映射”,不过我们还是叫它plane好啦。目前的Unicode字符分为17个planes,而每个plane拥有65536(即2^16)个代码点。可以认为一个plane就是一个范围的编码。

Plane 0也叫做BMP(Basic Multilingual Plane,基本多文种平面),存放着世界上各种语言与标记中最常用的字符。

Plane 1也叫做SMP(Supplementary Multilingual Plane,多文种补充平面),放着表情符号(emoji)、字母与数学符号、音乐符号、太玄经(太极符号)、装饰符号、扑克牌、麻将符号、箭头扩展和一些世界上各种语言不太常用的文字等等。

Plane 2也叫做SIP(Supplementary Ideographic Plane,表意文字补充平面),用于存放统一汉字(见4.2)的一些罕用字与汉藏语系其他语言的用字(如粤语用字)。

4.2. 统一汉字的分布

对于统一汉字(中日韩越统一表意文字,CJKV Unified Ideographs)来说,BMP存放着最初的版本(也是最常用字)与扩展A区的汉字。扩展B区到即将到来的扩展E区都放在SIP中。

在这些区中,除了独立字源的字,还有同一个字源或部首不同的变体或写法。比如“户”的第一笔,中国大陆与香港写作“户”,台湾写作“户”,日本则写作“戸”。这些差异也会在Unicode中用三个不同的编码去表示。所以B区到E区有不少此种字体。

举些B区的例子。网络上之前流行的“不会功夫不要艹我”被写成““xx巭嫑莪”,其中“xx”这个字就是在B区。而粤语“x鸡”(阉鸡)、“x完松”(和一个人发生关系后弃之而去)两个词的首字也是在B区。

5. utf8_unicode_ci和utf8mb4_unicode_ci的异同

这两种collations所对应的字符都是UTF-8编码的一个子集。utf8_unicode_ci最多能找到3个字节的Unicode编码,而utf8mb4_unicode_ci则能找到4个字节的编码。由于调整后的UTF-8编码格式规定最多使用4字节(原来是6字节)编码,所以utf8mb4系列可以说是覆盖了整个Unicode编码。

由于utf8_unicode_ci最多能找到3个字节的编码,意味着它只支持BMP中的字符,对于SMP与SIP以及其他头一字节不为0x00、需要4字节编码的planes来说,utf8_unicode_ci这种collation是无法支持。当使用4字节的字符(如emoji与B区以后的统一汉字)对使用此种collation的字段进行增删查改时,数据库会报一个非法字符的异常。而utf8mb4则没有此问题。由此也看出,utf8mb4_unicode_ci是utf8_unicode_ci的超集。

6. utf8mb4_unicode_ci的优缺点

utf8mb4系列的Collation在MySQL 5.5以上开始支持。相比起utf8_unicode_ci,它有如下的特性:

1) 在数据表中,对于BMP中的字符(最多使用3字节的字符,最常用的字符),两种collations具有完全相同的存储特性:相同的码值,相同的编码方式,相同的存储长度。不会增加任何的存储开销。

2) 在数据表中,对于其他plains的字符,utf8系列的collation根本不能存储,而utf8mb4系列的collations则可以存储。

3) 在数据表中,对于变长的字段(如VARCHAR2,TEXT),utf8mb4最大可存储的字符可能少于utf8系列的collation。

4) 在索引中,对于文本类型的字段,utf8mb4可索引的字符少于utf8系列的collations。如InnoDB的索引最多使用767字节。如果使用utf8mb4,每一个字符都会预留4字节做索引,而utf8则预留3字节。故此前者是191个字符,后者是255个字符。

5) 由于4)的原因,加上字符集大,utf8mb4的性能可能比utf8系列的collations低。

6) 若升级前的字段做了索引,需要把索引字符限制在191字符或以内。

7. 当前系统用哪个好

在当前的系统,全部都使用utf8_unicode_ci这种collation。但是在存储网页标题时,标题带有SMP或者SIP的字符,如emoji、粤语字,会引发数据库写入异常。于是,就有两种解决方向:

1) 扔掉。

1.1) 扔掉或截断引发异常的字。采取此种方法,需要对每一个标题进行扫描。

1.2) 扔掉整条记录。可以采取扫描法,或者扔掉引发异常的记录。

2) 升级到utf8mb4。会略为降低数据库性能。

7.1. 性能考虑

首先对于写入性能,查找字体的性能损耗由于在写入前字符都已经变成编码,基本可以忽略。对于网络传输的性能,则需要继续查找相关资料继续查证。但初步估计由于目前数据库在本地,故此这部分开销的增长不太明显。

而对于索引的性能,由于网页标题这一字段没有做索引,在可预见的将来也未有此计划,故此没有性能的损耗,也没有升级兼容性的担心。

况且,倘若走扔掉数据的方向,若采取扫描法,则需要付出扫描的开销。若采取扔掉记录法,则会先触发事务回滚,其他记录需要下次重新写入。而且当一批记录写入时有k个记录引发异常,则需要回滚与重试k次,除非使用扫描法预先扫描出这些异常的记录。但这也会引入额外的程序与数据库开销。若不使用事务,则数据库总体写入性能会大为降低。

虽然没有实测过,但从感觉上来定性判断,似乎扔掉记录比升级collation带来的性能退化要大。

7.2. 存储空间考虑

当前的网页标题是使用VARCHAR2存储。对于现在可用的、常见的BMP字符,不会引入额外的存储开销。BMP字符在VARCHAR的类型下不会为每一字符引入额外33%的空间开销。反之,定长的CHAR就会引入这种额外开销。

7.3. 目标数据考虑

网页标题作为以后特征分析的数据源。在分析需求完全没有确定的情况下,我认为扔掉任何数据都是不宜采取的办法,特别是整条记录扔掉更是不推荐。因为现阶段我们没有一套标准去判定何为有效数据、何为无效数据。有可能引发异常的那部分数据确实是没用的数据,也有可能那部分人群更倾向于在我们平台上活跃使用。既然各种可能性都存在,我们主动放弃一部分可能性,似乎不太恰当。

7.4. API设计与兼容性考虑

由于utf8_unicode_ci与utf8mb4_unicode_ci都是使用UTF-8编码,所以对于JAVA,使用MyBatis生成的代码是一样的,都是使用String类型。这点已经实测过。加上这两种collations在BMP中的编码完全一致,所以使用3字节与4字节的系统,对于BMP中的字符都是完全兼容、正常显示的。而对于3字节的系统,4字节的字符一般会显示成一个方框,或者在一个方框中有几个小数字,不会引发系统异常。

8. 总结

诚然,emoji对分词分析目前来说还没有什么效果,粤语词而且在SIP中也只是其中一部分,也不知道有多少日本动漫或者爱情动作片的网页会遇到这些生僻字,音乐符号也少人用,太极符号也不是每次都出现,一些数学增补的字符与箭头增补图案也不是每个人都会用。这些加起来可能不知够不够全部的千分之一。

但是倘若每一两个小时就会由于字符不能写入,引发数据库的异常。通过上面的分析,我认为增加这种兼容性带来的成本是可以接受的。

故此,我建议使用升级的方法,兼容所有Unicode字符。

emoji自诞生之初就一直存在着一个问题:每个人手机/电脑上的emoji看起来并不总是一样的。

emoji发明的初衷是为了让人们在网络上的聊天更加有趣和顺畅,但上面提到的这个问题却经常会影响人们使用emoji交流。

我们根据研究emoji这么久以来积累的经验,大致整理了几种比较常见的关于emoji显示的问题以及解决办法,希望能帮助到大家(≖ ◡ ≖)

那就话不多说,直接开始!

1. 同样的emoji在不同设备上不一样

如上图所示,同一批emoji在两个不同牌子的手机上看到的是不一样的。这是因为苹果、谷歌、微软等主流平台都对emoji有自己的一套设计,苹果手机理所当然的使用的是苹果的设计,而华为手机系统使用的则是谷歌的设计,所以就会产生这种差别了。

为什么emoji的设计不统一呢?我能不能在安卓手机上添加苹果的emoji?这些问题都可以在我们去年的这篇文章里找到答案平台不同,emoji表情还会变化?大家感兴趣的话可以看一下

2. emoji无法显示

三个月前苹果发布新emoji的更新之后,很多苹果用户就开始热火朝天地讨论和使用它们。

然而,其它手机品牌的用户却并不能在自己的手机中看见这些emoji。

正常显示的新emoji

不正常显示的四种形式

emoji之所以显示不出来,还得从它的本质说起(不好意思朋友们又双叒叕要重复一次这个话题

emoji和我们平时熟知的汉字、标点符号等一样,是一种全世界通用的可以被计算机识别的字符,由统一码联盟(Unicode Consortium)标准化管理。任何设备或者app如果想要支持emoji的使用,首先得把它们编入自己的系统中。

在统一码联盟的管理下,每个emoji都会有一个码点,这些码点就相当于emoji的身份z号一样。比如说,下图中emoji的码点是U+1F623。

:统一码联盟官网的截图

当你发送和接收一个emoji时,你的手机/电脑系统就会通过识别它的码点来寻找并显示它。而当系统遇到一个不认识的码点时,它就不知道该将这个码点显示成什么东西,所以emoji就变成了一个方框。

因此当你看到无法显示的emoji时,就说明你的系统还不认识它。那解决办法很简单啦,就是更新你的手机/电脑系统。

但是各个系统对emoji的更新并不是同步的,比如说苹果的更新速度就一直遥遥领先于其它系统......所以假如你并没有找到可以更新的版本或者更新后emoji还是无法显示,那就只能再耐心等待下一次更新了(或者换个牌子的手机

3. 一个emoji显示为两个emoji

正常显示的emoji

emoji被一分为二

这种情况对于不了解emoji的朋友来说可能会不太好分辨,如果在手机上看到的emoji像右边一样可能会以为真的是两个emoji。

这里顺便教你们一个分辨它的办法:如果你用鼠标双击/手指长按可以分别选中两个emoji,则说明它们是彼此独立的个体;假如你会一次性自动选中两个,就说明这两个emoji其实是一个整体。

至于为什么这些emoji会这样显示,是因为它们是由现有的emoji加上ZWJ(零宽度连字符)组合而成的。比如‍️=+ZWJ+️。

科普时间:这样做的目的是为了节约码点。由于每一个新的emoji都需要被分配码点,可码点位置是有限的,于是统一码联盟就决定用ZWJ连接现有的emoji来形成新的emoji。这样新emoji就无需占据一个新码点的位置了,它的码点就是组成它的几个emoji的码点的集合。比如,‍️的码点就是、ZWJ、️三者的码点的集合。

想要它们正常显示为一个emoji的话,同样是更新系统就可以啦。

4. 特殊情况

最后还有一种比较特殊的情况,就是当你使用同一台电脑浏览不同的网站时,你可能会发现同样的emoji在不同的网站显示的外观不一样。这不是系统导致的问题了,而是和emoji字体有关。

emoji表情的含义如下:

绘文字(日语:絵文字/えもじemoji)是日本在无线通信中所使用的视觉情感符号,绘指图画,文字指的则是字符,可用来代表多种表情,如笑脸表示笑、蛋糕表示食物等。在中国大陆,emoji通常叫做“小黄脸”。

词语来源

emoji就是表情符号,来自日语词汇“絵文字”(假名为“えもじ”,读音即emoji)。emoji的创造者是日本人栗田穰崇(Shigetaka Kurita),他将目光投向儿时的各种元素以获取灵感,如日本漫画和日本汉字等。

“日本漫画中有许多不同的符号。漫画家会画出一些表情,表现一个人满头大汗或是迸发出一个想法时头上出现一个灯泡。”同时,从日本汉字中他获得了一种能力,用简单的字符来表达“秘密”和“爱”等抽象概念。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/7356689.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-04
下一篇 2023-04-04

发表评论

登录后才能评论

评论列表(0条)

保存