每个emoji用对应一个Unicode码位,如:U+1F314(对应JS中UTF-16编码是:"\uD83C\uDF14"),汉字U+201D4,对应JS中的UTF-16编码是"\uD840\uDDD4"
在某些emoji字符后增加一个肤色修饰符改变emoji的肤色、可以将多个emoji通过连接符拼接成一个emoji,这些特殊规则使得在代码中判定emoji的长度、截取和对emoji做其他处理都比较困难。需要澄清的是:用一个Unicode字符修饰前一个字符不是emoji独有的,其他Unicode字符也存在,如:ü,由大写字母U(U+0055),后面跟一个连音符号(U+0308)组成。
码点/码位:Unicode编码空间中的一个编码,如,汉字的码位是201D4,通常表示为:U+201D4
2010年,Unicode正式收录了emoji,为每个emoji分配了唯一的码点。2011年,Apple在iOS中加入了标准的emoji输入键盘,2年后安卓系统也引入了emoji键盘。
基本emoji是指在Unicode编码表中用1个唯一码位表示的emoji
我们常见的emoji是彩色的,而常见的字体是黑色的。字符的颜色取决于字体文件,如果你愿意,你也可以把其常见的汉字字体设计成彩色的。iOS/MacOS的AppleColorEmoji字体是一种160x160的点阵字体,Android的NotoEmoji是一种128x128的点阵字体,而Windows使用的SegoeUIEmoji是一种矢量彩色字体。
字素集(graphemecluster)在Unicode中通常一个码点对应一个字符,但是Unicode引入了特定的机制允许多个Unicode码点组合成一个字形符号。这样由于多个码点组合成的一个字符称作字素集。比如ü是一个字素集,是由两个码点组成:大写字母U(U+0055),后面跟一个连音符号(U+0308)。再比如:'曙'.length=3、'♂'.length=7,前者由基本的曙字符加上一个变体选择符VS-17(见后文)组成,后者由多个基础emoji和修饰符、连接符组成。点开有惊喜[左边是一个.length为65的字素集,它是不可分割的一个字符]
可以动手验证一下
Unicode通过多个基础emoji组合的形式表示某些复杂emoji。组合的方式是在两个emoji之间添加一个U+200D,即:零宽度连接符(ZERO-WIDTHJOINER,简写为ZWJ),如:
可惜,有些emoji不是通过ZWJ组全emoji实现的,可能是因为没有赶上ZWJ定义的时机
Unicode中包含国旗符号,每个国旗也没有分配独立的码点,而是由双字符连字(ligature)来表示。(但Windows平台因为某些原因不支持显示,如果你是用Windows平台的浏览器阅读本文,只能说抱歉了)
...
前文的双字母连字机制支持将两个地区标识符连接在一起表示一个旗帜符号。标签序列与之类似,是Unicode中定义的一种更复杂的连接方式,格式是:基础emoji+一串拉丁标签字符(U+E0061~U+E007A)+结束符(U+E007F)如:+gbeng+U+E007F=其中是基础emojiU+1F3F4,_gbeng_分别代表对应的拉丁控制字符:g(U+E0067)、b(U+E0062)、e(U+E0065)、n(U+E006E)、g(U+E0067),U+E007F表示结束符,全称是TAGCANCEL
/***根据地区缩写返回对应的emoji*如:flag('gbeng')->*/functionflag(letterStr){ constBASE_FLAG=''; constTAG_CANCEL=String.fromCodePoint(0xE007F);//将普通字母字符序列转换为"标签拉丁字符"序列 consttagLatinStr=(letterStr.toLowerCase().split('').map(letter=>{ constcodePoint=letter.charCodeAt(0)-'a'.charCodeAt(0)+0xE0061;returnString.fromCodePoint(codePoint); })).join(''); returnBASE_FLAG+tagLatinStr+TAG_CANCEL;}目前用这种方式表示的emoji共有三个
共有12个键位符#*0123456789,规则是这样的:井号、星号和数字,加U+FE0F变成emoji,再加上U+20E3变成带方框的键位符。
一共有七种emoji造字法
前四种方法也可以组合使用,可构造非常复杂的emoji
U+1F6B5个人山地骑行
constvs=newVisualString('工作中');//vs.length=>4; //视觉长度//vs.physicalLength=>8; //字符串长度//vs[0]=>工//vs[3]=>//按照所见即所得的方式拆分字符//字素集方法//vs.substr(3,1)=>//截取字符//字素集属性//vs[3].physicalLength=>5//物理长度//vs[3].isEmoji=>true//是否是emoji我们将产出工具库中将要提供这些能力
如果A向B发送了一个组合emoji「工作123」,B的系统或软件中版本低(兼容的Unicode版本低)不支持该组合emoji,看到的可能会是「工作123」。用看到的是还是取决于用户的操作系统、软件和字体,我们提供的JS库无法感知到用户最终看到的是什么。我们提供的JS库会按照最新Unicode规范实现,无论用户看到的是什么都会把它当成一个字符(准确地说是字素集),即:constvs=newVisualString('工作123');vs.length=>6;vs[2]=>''有办法可以一定程度上解决上述问题,但是我们觉得可能不解决才是正确的做法。