我有一些数据表示为整数数组,最多可以包含20万个元素。整数值可以在0到200 000之间变化。

为了模拟此数据(出于调试目的),我可以执行以下操作:

let data = [];
let len = 200000
for (let i = 0; i < len; i++) {
    data[i] = i;
}


要将整数数组转换为unicode字符串,请执行以下操作:

let dataAsText = data.map((e) => {
    return String.fromCodePoint(e);
}).join('');


当我想转换回整数数组时,该数组似乎更长:

let dataBack = dataAsText.split('').map((e) => {
    return e.codePointAt(e);
});
console.log(dataBack.length);


它怎么来的?怎么了 ?

额外的信息:


我使用codePointAt / fromCodePoint,因为它可以处理所有unicode值(最多21位),而charCodeAt / fromCharCode失败。
例如,使用.join('123')和.split('123')将使变量dataBack与data的长度相同。但这不是一个很好的解决方案,因为字符串dataAsText的大小将不必要地变得很大。
如果let len等于或小于65536(最大值为2 ^ 16或16位),则一切正常。哪个奇怪?


编辑:

我使用codePoint是因为我需要将数据转换为unicode文本,以便数据简短。

有关codePoint与charCode的更多信息,并提供示例:
如果我们将150000转换为字符,则使用codePoint返回为整数:

console.log(String.fromCodePoint("150000").codePointAt(0));


这给了我们150000是正确的。对charCode进行相同操作失败,并显示18928(而不是150000):

console.log(String.fromCharCode("150000").charCodeAt(0));

最佳答案

这是因为较高的代码点值将产生2个字,如以下代码片段所示:



var s = String.fromCodePoint(0x2F804)
console.log(s);  // Shows one character
console.log('length = ', s.length); // 2, because encoding is \uD87E\uDC04

var i = s.codePointAt(0);
console.log('CodePoint value at 0: ', i); // correct

var i = s.codePointAt(1); // Should not do this, it starts in the middle of a sequence!
console.log('CodePoint value at 1: ', i); // misleading





在您的代码中,当您执行split时,会出错,因为组成字符串的单词都被拆分了,从而放弃了某些对旨在组合成单个字符的事实。

您可以对此使用ES6解决方案,其中spread syntax将此考虑在内:

let dataBack = [...dataAsText].map((e, i) => {
   // etc.


现在您的数量将是相同的。

例:



// (Only 20 instead of 200000)
let data = [];
for (let i = 199980; i < 200000; i++) {
    data.push(i);
}

let dataAsText = data.map(e => String.fromCodePoint(e)).join("");

console.log("String length: " + dataAsText.length);

let dataBack = [...dataAsText].map(e => e.codePointAt(0));

console.log(dataBack);





代孕

请注意,在0 ... 65535范围内,有保留给所谓的surrogates的范围,这些范围仅在与另一个值组合时表示一个字符。您不应迭代那些期望这些值自己代表字符的人。因此,在您的原始代码中,这将是另一个错误来源。

要解决此问题,您实际上应该跳过这些值:

for (let i = 0; i < len; i++) {
    if (i < 0xd800 || i > 0xdfff) data.push(i);
}


实际上,还有许多其他代码点不代表字符。

07-25 20:49
查看更多