【问题标题】:Emojis to/from codepoints in Javascript表情符号到/来自 Javascript 中的代码点
【发布时间】:2020-02-29 15:09:06
【问题描述】:

在我正在创建的混合 Android/Cordova 游戏中,我让用户以表情符号 + 字母数字的形式提供标识符 - 即 0..9、A..Z、a..z - 名称。例如

??????‍️堆栈溢出

在服务器端,用户标识符与 Emoji 和 Name 部分分开存储,只有 Name 部分要求是唯一的。游戏不时显示“联赛表”,因此用户可以看到他们与其他玩家相比的表现如何。为此,服务器发回由表情符号、姓名和分数组成的十个“高分”值序列。

然后,这将在一个包含三列的表格中呈现给用户 - 表情符号、名称和分数各一列。这是我遇到一个小问题的地方。最初我非常天真地假设我可以通过简单地查看handle.codePointAt(0) 来找出表情符号。当我意识到 Emoji 实际上可以是一个或多个 16 位 Unicode 值的序列时,我将代码更改如下

第 1 部分:剖析用户提供的“句柄”

var i,username,
    codepoints = [], 
    handle = "????‍️StackOverflow",
    len = handle,length; 

 while ((i < len) && (255 < handle.codePointAt(i))) 
 {codepoints.push(handle.codePointAt(i));i += 2;}

 username = handle.substring(codepoints.length + 1);

此时我已经有了“剖析”句柄

 codepoints =  [128587, 8205, 65039];
 username = 'Stackoverflow;

上面的i += 2handle.length 的使用说明。 This article 建议

  • handle.codePointAt(n) 将在您点击前导代理时返回完整代理对的代码点。在我的例子中,因为表情符号必须是第一个字符,所以表情符号的 16 位 Unicode 序列的主要代理是0,2,4...
  • 从同一篇文章中我了解到,Javascript 中的String.length 将返回16 位代码单元的数量

第二部分 - 为“联赛表”重新生成表情符号

假设我的服务器返回到应用程序的排名表数据具有表情符号字符 ????‍️ 的条目{emoji: [128583, 8205, 65039],username:"Stackexchange",points:100}。现在这是麻烦的事情。如果我这样做了

var origCP = [],
    i = 0, 
    origEmoji = '????‍️',
    origLen = origEmoji.length;

    while ((i < origLen) && (255 < origEmoji.codePointAt(i)) 
    {origCP.push(origEmoji.codePointAt(i);i += 2;}

我明白了

 origLen = 5, origCP = [128583, 8205, 65039]

但是,如果我从提供的数据中重新生成表情符号

 var reEmoji = String.fromCodePoint.apply(String,[128583, 8205, 65039]),
     reEmojiLen = reEmoji.length;

我明白了

reEmoji = '????‍️' 
reEmojiLen = 4;

因此,虽然 reEmoji 具有正确的表情符号,但它报告的长度已神秘地缩小到 4 个代码单元,而不是原来的 5 个。

如果我从重新生成的表情符号中提取代码点

var reCP = [],
    i = 0;

while ((i < reEmojiLen) && (255 < reEmoji.codePointAt(i)) 
{reCP.push(reEmoji.codePointAt(i);i += 2;} 

这给了我

 reCP =  [128583, 8205];

即使是 curioser,origEmoji.codePointAt(3) 给出了 9794 的尾随代理对值,而 reEmoji.codePointAt(3) 给出了下一个完整代理对的值 65039

此时我只能说

我真的在乎吗?

毕竟,我只想在单独的列中显示排名表表情符号,只要我得到正确的表情符号,引擎盖下发生的事情的细微之处就无关紧要了。但是,这很可能会为未来积累问题。

这里的任何人都可以了解正在发生的事情吗?

【问题讨论】:

    标签: javascript emoji utf-16 surrogate-pairs


    【解决方案1】:

    表情符号比单个字符更复杂,它们以“序列”的形式出现,例如zwj 序列(将多个表情符号组合成一个图像)或演示序列(提供同一符号的不同变体)等等,请参阅tr51 了解所有令人讨厌的细节。

    如果你像这样“转储”你的字符串

    str = "?‍️StackOverflow"
    
    console.log(...[...str].map(x => x.codePointAt(0).toString(16)))

    你会看到它实际上是一个(格式不正确的)zwj-sequence 包裹在一个表示序列中。

    因此,要准确地分割表情符号,您需要将字符串迭代为代码点数组(不是单位!)并提取平面 1 CP (>0xffff) + ZWJ 的 + 变体选择器。示例:

    function sliceEmoji(str) {
        let res = ['', ''];
    
        for (let c of str) {
            let n = c.codePointAt(0);
            let isEmoji = n > 0xfff || n === 0x200d || (0xfe00 <= n && n <= 0xfeff);
            res[1 - isEmoji] += c;
        }
        return res;
    }
    
    function hex(str) {
        return [...str].map(x => x.codePointAt(0).toString(16))
    }
    
    myStr = "?‍️StackOverflow"
    
    console.log(sliceEmoji(myStr))
    console.log(sliceEmoji(myStr).map(hex))

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-12-10
      • 2018-07-03
      • 1970-01-01
      • 2012-06-15
      • 1970-01-01
      • 2018-07-19
      • 2020-11-01
      • 1970-01-01
      相关资源
      最近更新 更多