emoji探究

1,004 阅读3分钟

Unicode 和 UTF-16

Unicode 是一个字符集,他的起源于想把全世界所有的字符都包含在一个集合里,用一个码点表示(形如U+1F469),这样就不会存在乱码。

Javascript语言支持Unicode字符集,但是只有一种编码方法,由最初的 UCS-2编码 演变为现在的 UTF-16编码,所以如果在Javascript中操作emoji,需要对其UTF-16编码进行匹配。

如何查看字符的UTF-16编码?

function getUTF16(str) {
  return Array.prototype.map.call(str, (item) => {
    const code = item.charCodeAt();
    return '\\u' + code.toString(16).toUpperCase();
  }).join('');
};

// UTF-16编码转化为字符串
function getStr(utf16) {
  return JSON.parse(JSON.stringify(utf16));
}

emoji

大多情况下,emoji有2个字节,对应着一个固定的Unicode码点,在不同的平台(Apple、安卓、Github、Facebook等)会有不同的表现。

比如笑脸图😀,其Unicode码为 U+1F600,其UTF-16码为 \uD83D\uDE00,为双字节,在不同的平台,即使Unicode码相同,但是具体展示样式是由平台本身确定

某些emoji,比如✌,其Unicode码为 U+270C,UTF-16码为 \u270C,为单字节。

所有emoji对应的Unicode码查看,通过该链接内容,可以观察到emoji以下的特点:

  • 不同平台的emoji样式不统一
  • emoji可能存在多个unicode的组合
  • emoji的Unicode可能不是连续的
  1. 组合emoji

特定的Unicode可以表示emoji外,还可以通过多个Unicode码组合表示一个emoji

比如,U+1F468👨 U+1F469👩 U+1F467👧,这3个码点通过 "零宽度连接符"(U+200D)链接起来,U+1F468 U+200D U+1F469 U+200D U+1F467👨‍👩‍👧 如果系统不支持这种用法的话,还是会单独拆分开emoji展示的,U+1F468U+200DU+1F469U+200DU+1F467👨👩👧

  1. 正则解析

因为emoji数量庞大,想要完全覆盖的话,需要归纳分析

[\uD83C|\uD83D|\uD83E][\uDC00-\uDFFF][\u200D|\uFE0F]{0,2}

  • 大部分双字节emoji的Unicode区间在[U+1F17 ~ U+1FAD6] = [\uD83C\uDD70 ~ \uD83E\uDED6],范围在 [\uD83C|\uD83D|\uD83E][\uDC00-\uDFFF];
  • 匹配 \u200D 链接的 组合emoji,形如 \uD83E\uDDD1\u200D\uD83C\uDF93 🧑‍🎓 = [emoji][emoji];
  • 部分emoji是以 \uFE0F 结尾;

[\u2764\uFE0F\u200D]

  • 匹配特殊 emoji: ❤️‍

[\u2642|\u2640]\uFE0F

  • 匹配特殊 emoji: ♂️ ♀️

[\u26F9|\u26A7|\u2620][\u200D|\uFE0F]

  • 匹配特殊 emoji: ⛹️ ⚧️ ☠️

[\xA9\xAE\u203C\u2049\u2122-\u2B55\u2139\u2194-\u2199\u21A9\u21AA\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u2600-\u2604\u260E\u2611\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26B0\u26B1\u26C8\u26CF\u26D1\u26D3\u26E9\u26F0\u26F1\u26F4\u26F7\u26F8\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2763\u2764\u27A1\u2934\u2935\u2B05-\u2B07\u3030\u303D\u3297\u3299]

  • 部分单字节emoji的Unicode码,并非连续的,抽出单个UTF-16码进行匹配,形如 \xA9 © \xAE ®

[#*0-9]\uFE0F\u20E3

  • 匹配 数字键盘类型的emoji,#\uFE0F\u20E3 #️⃣ 1\uFE0F\u20E3 1️⃣