1.前言
Emoji表情在通讯场景被广泛使用,最近处理bug单时就遇到了相关问题,在解决问题的过程中重新认识了下Java的字符编码,故形成此文。
String emostring ="😂😍🎉👍";
上述字符串中包含4个Emoji表情,从直观上我们认为其长度应该为4,但是通过如下代码计算其长度,会发现其长度与我们的直观感觉不同,具体如下所示:
由上图可知,通过length()方法可得emostring(代码中的字符串会被转义为unicode字符串)字符串长度为8。
这是因为Java将字符串存储为UTF-16编码,emostring字符串中的每个表情均使用两个UTF-16字符串编码组成,因此其长度为8。如果我们要获取字符串中Emoji表情的个数,可以通过调用emostring.codePointCount(0, emostring.length())
获取,返回值为4。
2. Emoji长度
'⛱'.length == 1,'😉'.length == 2,'👩👩👧👧'.length == 11,可以看到每个Emoji表情的长度不一致。
Emoji 是 Unicode 字符集的一部分,其组成方式为:字节组合成字符编码单元(或者叫做代码点,unicode number),而字符编码单元组合成字形(视觉符号,visual symbols)。在 UTF-16 编码字符串中,Emoji 的长度可能是 1 或 2 甚至更多。
'⛱' = '\u26f1'
'😉' = '\ud83d\ude09'
'👩👩👧👧' = '\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d\udc67'
此外,还有一种情况,即Emoji表情由多个 Emoji+一些额外的字符拼接出来的,像 '👩👩👧👧' 就是由 ['👩', '', '👩', '', '👧', '', '👧'] 拼接而成的,单个 Emoji 长度为 2,中间的连接字符长度为 1,故长度值为11(调用length计算)。
不过比较挠头的是,此时使用codePointCount()
计算👩👩👧👧长度,会发现其长度为7,无法将这个由多个Emoji表情拼接的字形正确计算为1。
3. 补充
Java字符串采用UTF-16编码(Javascript亦采用UTF-16),这与现在WEB编程界广泛采用的UTF-8编码格式存在差异,这导致在涉及字符串长度计算的时候需要多加小心。例如Golang字符串采用UTF-8编码,这就导致Java和Golang计算出来的长度不一致。
解决此类的问题方案就是均采用UTF-8编码格式计算字符串长度,这样可以达成前后端与多端(iOS、Android)统一。