不要小看小小的emoji 表情

文章推薦指數: 80 %
投票人數:10人

UTF-8 前言好久没更新了,最近事比较多,或许下个月就会恢复到正常的发文频次。

这篇文章得从一个emoji表情开始,我之前开源的一个IM项目中有朋友提到希望可以支持emoji表情传输。

https://github.com/crossoverJie/cim/issues/12 正好那段时间有空,加上这功能看着也比较简单准备把它实现了。

但在真正实现时却发现没那么简单。

我首先尝试将一个emoji表情存入数据库看看: 果不其然的出错了,导致这个异常的原因是目前数据库所支持的编码中并不能存放emoji,那emoji表情到底是个什么东西呢。

本质上来说计算机所存储的信息都是二进制01,emoji也不例外,只要存储和读取(编解码)的方式一致那就可以准确的展示这个信息。

更多编解码的内容后文再介绍,这里先想想如何快速解决问题。

存储emoji虽说想要在MySQL中存储emoji的方式也有好几种,比如可以升级存储字符集到可以存放emoji,但这种需要MySQL的版本支持。

所以更保险的方式还是在应用层解决,比如我们是否可以将emoji当做字符串存储,只是显示的时候要格式化为一个emoji表情,这样对于所有的数据库版本都可兼容。

于是我们这里的需求是一个emoji表情转换为字符串,同时还得将这个字符串转换为emoji。

为此我在GitHub上找到了一个库,它可以方便的将一个emoji转换为字符串的别名,同时也支持将这个别名转换为emoji。

https://github.com/vdurmont/emoji-java 12345678910@Testpublicvoidemoji()throwsException{Stringstr="An:grinning:awesome:smiley:string😄withafew:wink:emojis!";Stringresult=EmojiParser.parseToUnicode(str);System.out.println(result);result=EmojiParser.parseToAliases(str);System.out.println(result);} 所以基于这个基础库最终实现了表情功能。

其实它本质上是自己维护了一个emoji的别名及它的Unicode编码(本质上是UTF-16)的映射关系,再每次格式化数据的时候都会从这个表中进行翻译。

编码知识回顾自此需求是完成了,但还有几个问题待解决。

Java中是如何存储emoji的? emoji是如何进行编码的? ASCII在谈emoji之前非常有必要了解下计算机编码鼻祖的ASCII码。

大家现在都知道在计算机内部存储数据本质上都是二进制的0/1,对于一个字节来说有8位;每一位可以表示两种状态,也就是0或1,这样排列组合下来,一个字节就可以表示256(2∧8)种不同的状态。

对于美国来说他们日常使用的英语只需要26个英文字母,再加上一些标点符号就足够用计算机来进行信息交流。

于是上个世纪60年代定义了一套二进制与英文字符的映射关系,可以表明128个不同的英文字符,也就是现在的ASCII码。

这样我们就可以使用一个字节来表示现代英文,看起来非常不错。

Unicode随着计算机的发展,逐渐在欧洲、亚洲地区流行;再利用这套ASCII码进行信息交流显然是不行的,很多地区压根就不使用英文,而且也远超了128位字符(中文就更不用说了)。

虽说一个字节在ASCII码中只用了128位,但剩下(258-128)的依然不足用用于描述其他语言。

这时如果能有一种包含了世界上所有的文字的字符集,每一个地区的文字都在这个字符集中有唯一的二进制表示,这样便不会出现乱码问题了。

Unicode就是来做这个的,截止目前Unicode已经收录了10W+的字符,你所能使用的字符都包含进去了。

UTF-8Unicode虽说包含了几乎所有的文字,但在我们日常使用好像很少看到他的身影,我们用的更多的还是UTF-8这样的编码规则。

这也有几方面的原因,比如说除开英文,其他大部分的文字都需要用2个甚至更多的字节来表示;如果统一都用Unicode来表示,那必然需要以占用字节最多的字符长度为标准。

比如汉字需要2个字节来表示,而英文只需要一个字节;这时就得规定2个字节表示一个字符,不然汉字就没法表示了。

但这样也会带来一个问题:用两个字节表示英文会使得第一个字节完全是浪费的,如果一段信息全是英文那对内存的浪费是巨大的。

这时大家应该都能想到,我们需要一个可变的长度的字符编码规则,当是英文时我们就用一个字节表示,甚至可以完全兼容ASCII码。

UTF-8便是实现这个需求的,它利用两种规则可以表示一个字节以及多字节的字符。

大致规则如下: 当第一个字节的第一位为0时便表示为单字节字符,此时和ASCII码一致,完全兼容。

当第一个字节为1时,有几个1便代表是几个字节Unicode字符。

这样便可根据字符的长度最大程度的节省存储空间。

当然还有其他的编码规则,比如UTF-16、UTF-32,平时用的不多,但本质上都和UTF-8一样,都是Unicode的不同实现,也是用于表示世界上大部分文字的字符集。

Java中的emoji现在来回到本次的主题,emoji。

刚才说到Unicode包含了世界上大部分的字符,emoji自然也不例外。

https://apps.timwhitlock.info/emoji/tables/unicode 这个表格中包含了所有的emoji以及它所对应的Unicode编码,同时也有对应的UTF-8编码的实现。

从图中也可以看出emoji表情用UTF-8表示时会占用4个字节,那在Java中它会是怎么存储的呢? 很简单,debug一下就知道了。

在Java中也是通过char来存储emoji的,char作为基本数据类型会占用2个字节;从刚才的图中可以看出,emoji使用UTF-8会占用四个字节,这样很明显char是没法存储的,所以在这里其实是使用UTF-16编码进行存储。

基于这个原理,我们也可以自己实现将一个emoji表情转换为字符串,同时也可通过字符串转换为emoji。

总结从这次研究emoji可以看出,任何一门基础知识都是应用的根基,在计算机行业尤为突出,希望大家看完这篇能回忆起大学课堂被老师支配的恐惧😂。

随便提一下,相关源码可在这里查看: https://github.com/crossoverJie/cim 你的点赞与分享是对我最大的支持 我很有眼光! 请我吃🍗 赏 微信打赏 支付宝打赏 热评文章 TableofContents Overview crossoverJie Youneverknowwhatyoucandotillyoutry. 139 posts 62 categories 141 tags RSS GitHub 简书 掘金 Twitter 友情链接 Jark'sBlog 嘟嘟独立博客 GiraffeHome 潘小鶸(ruò) Format'sNotes BenedictJin 程序猿DD 小柒博客 Java技术驿站 vim教程网 jitwxs 江南一点雨 松花皮蛋的黑板报 FutureiDeal Cryptospace 1.前言2.存储emoji3.编码知识回顾3.1.ASCII3.2.Unicode3.3.UTF-84.Java中的emoji5.总结



請為這篇文章評分?