在连接使用String.fromCharCode创建的字符串时,Array.join会插入额外的字符

时间:2017-07-15 03:52:09

标签: javascript character-encoding fromcharcode

我有一个字节数组,我要将其编码为一个字符串,以便传递给浏览器中的btoa。这些字节使用完整的0-255范围。我在btoa看到了一开始似乎是一个错误,但是javascript的Array.prototype.join却是一个bug(或者至少是非常意外的行为)。为了说明这个问题,我将从一些base64编码的数据开始:

gACJNqQ0cg==

这可以解码为字节数组,如下所示:

atob('gACJNqQ0cg==').split('').map(c => c.charCodeAt(0))
> [128, 0, 137, 54, 164, 52, 114]

现在,您希望能够撤消操作并返回原始字符串:

btoa([128, 0, 137, 54, 164, 52, 114].map(String.fromCharCode).join(''))

但相反,你得到一个更大的字符串:

gAAAAAEAiQIANgMApAQANAUAcgYA

进一步调查时,连接使用String.fromCharCode创建的任何字符串时会出现问题:

'Hi'.split('').join('').length
> 2
'Hi'.split('').map(c => c.charCodeAt(0))
> [72, 105]
[72, 105].map(String.fromCharCode).join('').length
> 6
//what?

我在任何地方都看到了这种行为:Chrome(60),Firefox(53)和Node(6.9.4)。在浏览器中,您没有简单的替代方案,例如节点 new Buffer(array, 'binary').toString('base64')解决此问题。如何从字节值数组中安全地创建字符串,可以将其传递给btoa

2 个答案:

答案 0 :(得分:1)

如果您在map中指定了箭头功能而不是直接将String.fromCharCode方法传递给它,那么您的代码适合我:

console.log(btoa([128, 0, 137, 54, 164, 52, 114].map(x => String.fromCharCode(x)).join('')));

答案 1 :(得分:0)

我找到了解决这个复杂问题的简单方法:字符串连接。这是一个例子:

let str = '';
[128, 0, 137, 54, 164, 52, 114].forEach(c => {
    str += String.fromCharCode(c);
});

str.length
> 7
btoa(str)
> 
).join('').length

它可以工作,并且对于不是很大的字符串应该表现得足够好。但我希望看到一个更好,更清洁的解决方案,甚至只是为了更全面地了解String.fromCharCode和Array.prototype.join所发生的事情。