如何选择TextDecoder的编码以匹配String.fromCharCode的输出结果?
如何选择TextDecoder的编码以匹配String.fromCharCode的输出结果?
嘿,我来帮你理清楚这个问题!你现在碰到的核心问题是:为什么用String.fromCharCode(...data)和TextDecoder('latin1')解码同一个Uint8Array,得到的字符串不一样,导致btoa报错?其实答案很简单——你应该用'iso-8859-1'这个编码,而不是'latin1'。
为什么会不一样?
先给你拆解下背后的坑:
String.fromCharCode(...data)的行为是把每个字节数值(0-255)直接映射成Unicode码点U+0000到U+00FF的字符,包括0x80-0x9F范围内的C1控制字符(这些字符在UTF-16里是没有对应可见符号的,就是纯控制符)。- 而你用
TextDecoder('latin1')的时候,看起来像是符合预期,但实际上在大部分JS环境(比如浏览器)里,'latin1'这个编码名被偷偷映射成了Windows-1252,而不是严格的ISO-8859-1。Windows-1252把0x80-0x9F这些原本的控制字符替换成了可见的特殊符号(比如0x80对应€,0x82对应‚),这些符号的Unicode码点都超过了255,自然会触发btoa的报错——因为btoa只接受每个字符码点在0-255之间的字符串。
为什么iso-8859-1是对的?
TextDecoder('iso-8859-1')的行为完全贴合String.fromCharCode的逻辑:它会把Uint8Array里的每个字节0xXX直接映射成Unicode码点U+00XX的字符,从U+0000到U+00FF一个不差,包括那些C1控制字符。这样解码出来的字符串,和你用String.fromCharCode(...data)得到的结果完全一致,传给btoa也不会有任何问题。
用你的测试用例验证
用你那个覆盖0-255所有数值的Uint8Array测试:
const array = Array.from({ length: 256 }, (_, i) => i); const d = new Uint8Array(array);
- 用
String.fromCharCode(...d)得到的是U+0000到U+00FF的完整字符集,其中0x80-0x9F是纯控制符; - 用
new TextDecoder('iso-8859-1').decode(d)得到的字符串和上面完全一样,不会出现€、‚这类Windows-1252的特殊符号; - 再把这个字符串传给
btoa,就能和第一个函数的结果完全匹配了。
补充一点小知识
之前你以为latin1和UTF-16前256个字符重叠,这个说法没错,但前提是严格的ISO-8859-1。而Windows-1252是ISO-8859-1的超集,替换了C1控制字符,这才是导致你两个方法结果不同的罪魁祸首。
备注:内容来源于stack exchange,提问作者Newbie
相关产品推荐
相关产品推荐

