一、emoji与零宽连接符的应用
1、Emoji ZWJ Sequences
一般的 emoji 的字符是 3 个字节或 4 个字节, 像 ❤️ 这种看起来只有单个字符的 emoji 之所以它的 size 远超过 4 字节,是因为它是由若干个 emoji 按顺序连接组成的,这种顺序叫做 emoji zwj sequences 。
2、零宽连接符
实际上,并不是把 ❤️ 这三个 emoji 并排在一起就能够自动组成一个 ❤️ 。这三个 emoji 之间是需要通过一个 zwj 字符来连接的,也就是 “ zwj ❤️ zwj ”。
那么什么是 zwj 呢?zwj 全称 zero width joiner,也就是 “零宽连接符”。因为这个字符是零宽度的,所以我们是看不见这个字符的。根据名字我们就可以知道,zwj 的作用就是用于字符与字符之间的连接。
zwj 的 unicode point 是 U+200D
同样,在 emoji 中还有非常多类似的组合式 emoji,比如:
二、Emoji在JavaScript中的应用
1、在写 JavaScript 字串的時候,直接将 Emoji 字元写入字符串是可以的,例如
var a = '';
2、JavaScript 有个 Unicode escape sequences 表示法,可以用在字串中,假设 Unicode 的字码为 U+1F197
( ),那么 JavaScript 有2种表示法:
(1)ES6 (ES2015) 可以使用 Unicode 的 Code point (码点) 表示一个 Unicode 文字
var emoji1 = '\u{01F354}';
var emoji2 = String.fromCodePoint(0x1F354);
注意:即便 ES6 可以用 Unicode 的 Code point 來表示一个 Unicode 文字,但事实上內部的文字码点主要还是以 UTF-16 为主。
(2)ES5 仅支持 \uhhhh
表示法,大部分 Emoji 字元被定义在 BMP 以外的字码区域,你必須把一个 Unicode 字碼码(Code point) 转换成2个 UTF-16 码元 (code unit) 才行,通过 surrogate pair 的方式来表达一个 Unicode 字元。所以 U+1F197
只能用以下语法来写:
'\uD83C\uDD97'
你可以通过 ES6 (ES2015) 提供的 API 来计算出 ES5 可以使用的2个 UTF-16 码元 (code unit):
var hb = '\u{01F197}'[0].codePointAt(0).toString(16); // \ud83c
var lb = '\u{01F197}'[1].codePointAt(0).toString(16); // \udd97
也可以通过以下函数将 UTF-32 字码转换为2个 UTF-16 的表示法:
function toUTF16(codePoint) {
var TEN_BITS = parseInt('1111111111', 2);
function u(codeUnit) {
return '\\u'+codeUnit.toString(16).toUpperCase();
}
if (codePoint <= 0xFFFF) {
return u(codePoint);
}
codePoint -= 0x10000;
// Shift right to get to most significant 10 bits
var leadingSurrogate = 0xD800 | (codePoint >> 10);
// Mask to get least significant 10 bits
var trailingSurrogate = 0xDC00 | (codePoint & TEN_BITS);
return u(leadingSurrogate) + u(trailingSurrogate);
}
3、将 12 个按键符号转换为 Emoji
Emoji 定义了 12 个按键符号(0123456789#*
),只要加入一组 2 个字元的 Emoji Keycap Sequence ('\uFE0F\u20E3'
) 就可以把文字自动转成 Emoji。
4、在现有的 Emoji 字元后方加入菲茨派屈克修饰符(虚色深度)
在 Emoji 表情的 Unicode 规格中,有个特別的 EMOJI MODIFIER FITZPATRICK (菲茨派屈克修饰符) 可用,這個 修饰符 (Modifier) 也是一个合法的 Unicode 字元,必須紧接着在 Emoji 字元后面出现。
目前全世界人类的 虚色分级 (Fitzpatrick scale) 是 1975 年由一位叫做 Thomas B. Fitzpatrick 的人制定出來的,他当初定义了 6 种虚色等級。(Type 1 ~ Type 6)。研究 Emoji 竟然还能学到这种冷知识。
在 Emoji 表情符符中,总共定义了 5 个字元,代表 Emoji 的颜色深度。为什么不是 6 个呢?因为 Type 1 与 Type 2 颜色太相近了,在电脑屏幕上不容易区分,索性就合并了。这5个字元分別是:
以下是不同的 Emoji 在加上菲茨派屈克修飾符之后的比较
var adult = '';
var fitz6 = '\uD83C\uDFFF';
var black = adult + fitz6; // 只要透過簡單的字串相加就可以完成!
console.log(black);
这样就会出现一个黑人。
注意:不是所有 Emoji 都能加上虚色,只有跟「人类」有关的 Emoji 才能用,例如 Emoji 中有出現脸、手、脚、身体的,都可以这样用。目前 Unicode v11.0 定义了 106 个 Emoji 是可以加上 EMOJI MODIFIER FITZPATRICK 字元的,完整清单可以参考这里。
5、通过零宽连字符(ZWJ) 将多个Emoji 连接在一起
我以前一直很纳闷有些 Emoji 到底是怎样产生的,深入研究后才发现,原谅 Emoji 这么好玩,除了有几千种不同的 Emoji 之外,还可以将其组合成各种千变万化的玩法。
Unicode 中有个特殊的 零寬連字(ZWJ) 符號 (U+200D
),这基本上是一个合法的 Unicode 文字,只是他预设是看不见的零宽(Zero Width) 字元。这个字元通常用在排版用途,不过却被 Emoji 拿来用了。你可以通过这个字元,任意串接2个不同的 Emoji 字元,然后就可以创造出新的、不存在 Emoji 清单中的全新 Emoji 字元。
我直接把 (男人) 与 (女人) 串加起來,但中间卡一个 ZWJ 字元,这个 Emoji 就会自动变成 (一男一女):
如果希望显示一家三口全家福的 Emoji ,可以直接把 (男人) 、 (女人) 与 (男孩) 串加起來,但不同的字元中间都要加一个 ZWJ 字元,Emoji 就会自动变成 (一男一女外加一个男孩)
基本上,你要加几个人都可以,是不是很好玩。