我肯定遗漏了一些关于TextEncoder和TextDecoder行为的东西。在我看来,下面的代码应该是往返的,但似乎并非如此:
new TextDecoder().decode(new TextEncoder().encode(String.fromCharCode(55296))).charCodeAt(0);因为我只是对字符串进行编码和解码,所以char代码看起来应该是相同的,但是返回的是65533而不是55296。我遗漏了什么?
发布于 2021-02-21 02:04:08
基于一些拼写,TextEncoder.encode()方法出现在用一个类型的论点 USVString中,USV代表Unicode值。根据此页,USV不能是高代理项或低代理代码点.
此外,根据MDN:
USVString是Unicode标量值的序列。这个定义不同于DOMString或JavaScript字符串类型,因为它总是表示一个适合文本处理的有效序列,而后者可以包含代理代码点。
因此,我猜您对encode()的String参数正被转换为USVString (隐式或在encode()中)。基于此页,它看起来像是从String转换为USVString,它首先将它转换为DOMString,然后是遵循这个程序,包括用U+FFFD替换所有代理,这是您看到的代码点65533,“替换字符”。
我认为String.fromCharCode(55296).charCodeAt(0)工作的原因是因为它不需要进行String -> USVString转换。
至于为什么TextEncoder.encode()是这样设计的,我不太了解unicode的细节,无法尝试解释,但我怀疑这是为了简化实现,因为它支持的唯一输出编码似乎是Uint8Array中的UTF-8。我猜需要一个没有代理的USVString参数(而不是一个本地的UTF-16 String (可能带有代理)将编码简化为UTF-8,或者可能使一些编码/解码用例更简单?)
发布于 2022-02-18 19:06:48
对于那些(像我一样)不确定什么是"unicode代理“的人:
问题所在
字符代码55296本身不是一个有效的字符。因此,代码的这一部分已经成为一个问题:
String.fromCharCode(55296)由于该charCode中没有有效字符,因此.fromCharCode函数将返回错误字符"�“,该字符恰好有代码65533。
像55296这样的代码仅作为一对代码的第一个元素有效。代码对用于表示Unicode的基本多语言平面中不适合的字符。(在基本的多语言平面之外有很多字符,所以它们需要两个16位数字来编码。)
例如,下面是代码55296的有效用法:
console.log(String.fromCharCode(55296, 57091)它返回的字符"",从古老的伊特鲁里亚字母表。
解决方案
此代码将正确地往返:
const code = new TextEncoder().encode(String.fromCharCode(55296, 57091));
console.log(new TextDecoder().decode(code).charCodeAt(0)); // Returns 55296但是要小心:.charCodeAt只返回对的第一部分。一个更安全的选择可能是使用String.codePointAt将字符转换为单个32位代码。
const code = new TextEncoder().encode(String.fromCharCode(55296, 57091));
console.log(new TextDecoder().decode(code).codePointAt(0)); // Returns 66307https://stackoverflow.com/questions/66298005
复制相似问题