3

我正在处理包含 UTF 星体符号代理一半的转义序列的原始字符串。(我想我说得对……)

console.log("\uD83D\uDCA9")
// => 

让我们以上面的表情符号为例。如果我有代理对 (\uD83D\uDCA9) 我怎样才能反过来将它的十六进制值转换为 JavascriptString.fromCodePoint()函数的有效参数?

我尝试了以下方法:

const codePoint = ["D83D", "DCA9"].reduce((acc, cur) => {
    return acc += parseInt(cur, 16);
}, 0);

console.log(String.fromCodePoint(codePoint));
// =>  (some weird symbol appears, not !)

PS:我熟悉 ES6 转义序列,它在括号 {...} 之间显示十六进制值,而不是使用代理半部分。但我需要用代理对来做到这一点!

非常感谢任何建议。

4

2 回答 2

3

您可以将值列表传递给函数:

console.log(String.fromCodePoint(0xd83d, 0xdca9));

因此,“有效参数”String.fromCodePoint()不一定是单个值,实际上对于需要代理对的字符,根据定义它不能是单个值。为什么?因为就所String.fromCodePoint()关心的而言,每个单独的数字源值都必须是 16 位(2 字节)值。如果您可以传递更大的单个数字,则不需要代理对!

编辑:以上段落的大部分内容都不准确;该.fromCodePoint()方法接受完整的 Unicode 代码点值(大于 16 位)。当然它仍然必须将它们拆分为代理对,因为 JavaScript 字符串是 UTF-16,但这意味着如果您碰巧有全尺寸的 Unicode 代码点,您不必自己将它们拆分,这很好. 但是,如果您确实已经有对,那么您自己将它们组合起来确实没有意义,因为当作为点列表的一部分传递时,该方法也适用于对。

如果数组中有值,则可以使用以下命令调用该函数apply

var points = [0xd83d, 0xdca9];
console.log(String.fromCodePoint.apply(String, points));
于 2018-12-20T17:43:21.813 回答
2

Pointy 的解决方案是正确的,但要回答您的问题,您的公式出了什么问题,问题是您只需添加 0xD83D 和 0xDCA9,导致 0x1B4E6。但这不是代理人的工作方式。你应该使用正确的公式

( (first - 0xD800) << 10) + (second - 0xDC00) + 0x10000

可以缩短为

(first - 0xD7F7) << 10) + second

请参阅Unicode 编码

如果你这样做,你会得到 0x1F4A9。

const codePoint = ["D83D", "DCA9"].reduce((acc, cur) => {
  cur = parseInt(cur, 16); return acc += cur<0xDC00 ? (cur-0xD7F7)<<10 : cur;
  }, 0);

console.log(String.fromCodePoint(codePoint));
// => now outputs !

于 2018-12-21T09:25:43.230 回答