Unicode 代理项对和 String.fromCodePoint() — JavaScript
Unicode surrogate pairs and String.fromCodePoint() — JavaScript
我正在处理包含转义序列的原始字符串,用于替代 UTF 星体符号的一半。 (我想我没听错……)
console.log("\uD83D\uDCA9")
// =>
我们以上面的表情符号为例。如果我有代理项对 (\uD83D\uDCA9),我怎样才能依次获取它的十六进制值并将其转换为 Javascript 的 String.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 转义序列,它在括号 {…} 之间显示十六进制值,而不是使用代理项。 但是我需要用代理对来做这个!
非常感谢任何建议。
您可以将 列表 值传递给函数:
console.log(String.fromCodePoint(0xd83d, 0xdca9));
因此 String.fromCodePoint()
的 "valid argument" 不一定是单个值,实际上对于需要代理对的字符,根据定义 不能 一个单一的价值。为什么?因为就 String.fromCodePoint()
而言,每个单独的数字源值都必须是 16 位(2 字节)的值。如果你能传递更大的单数,就不需要代理对了!
编辑:以上段落的大部分内容不准确; .fromCodePoint()
方法 将 接受完整的 Unicode 代码点值(大于 16 位)。当然,它仍然需要将它们拆分为代理项对,因为 JavaScript 字符串是 UTF-16,但这意味着如果您碰巧拥有全尺寸 Unicode 代码点,则不必自己拆分它们, 这很好。但是,如果您 do 已经有了对,那么您自己组合它们真的没有意义,因为该方法在作为点列表的一部分传递时也适用于对。
如果数组中有值,可以使用 apply
:
调用函数
var points = [0xd83d, 0xdca9];
console.log(String.fromCodePoint.apply(String, points));
Pointy 的解决方案是正确的,但要回答您的问题,您的公式出了什么问题,问题是您只需添加 0xD83D 和 0xDCA9,得到 0x1B4E6。但这不是代理人的工作方式;你应该使用正确的公式
( (first - 0xD800) << 10) + (second - 0xDC00) + 0x10000
可以缩短为
(first - 0xD7F7) << 10) + second
如果你这样做,你会得到 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 !
我正在处理包含转义序列的原始字符串,用于替代 UTF 星体符号的一半。 (我想我没听错……)
console.log("\uD83D\uDCA9")
// =>
我们以上面的表情符号为例。如果我有代理项对 (\uD83D\uDCA9),我怎样才能依次获取它的十六进制值并将其转换为 Javascript 的 String.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 转义序列,它在括号 {…} 之间显示十六进制值,而不是使用代理项。 但是我需要用代理对来做这个!
非常感谢任何建议。
您可以将 列表 值传递给函数:
console.log(String.fromCodePoint(0xd83d, 0xdca9));
因此 String.fromCodePoint()
的 "valid argument" 不一定是单个值,实际上对于需要代理对的字符,根据定义 不能 一个单一的价值。为什么?因为就 String.fromCodePoint()
而言,每个单独的数字源值都必须是 16 位(2 字节)的值。如果你能传递更大的单数,就不需要代理对了!
编辑:以上段落的大部分内容不准确; .fromCodePoint()
方法 将 接受完整的 Unicode 代码点值(大于 16 位)。当然,它仍然需要将它们拆分为代理项对,因为 JavaScript 字符串是 UTF-16,但这意味着如果您碰巧拥有全尺寸 Unicode 代码点,则不必自己拆分它们, 这很好。但是,如果您 do 已经有了对,那么您自己组合它们真的没有意义,因为该方法在作为点列表的一部分传递时也适用于对。
如果数组中有值,可以使用 apply
:
var points = [0xd83d, 0xdca9];
console.log(String.fromCodePoint.apply(String, points));
Pointy 的解决方案是正确的,但要回答您的问题,您的公式出了什么问题,问题是您只需添加 0xD83D 和 0xDCA9,得到 0x1B4E6。但这不是代理人的工作方式;你应该使用正确的公式
( (first - 0xD800) << 10) + (second - 0xDC00) + 0x10000
可以缩短为
(first - 0xD7F7) << 10) + second
如果你这样做,你会得到 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 !