4

我遇到了一个问题,不幸的是,我还没有找到正确的解决方案:我需要解码使用 windows-1251 (cp1251) 编码的 url-slice。

我知道有这些方法 - decodeURI()decodeURIComponent(),但它们仅适用于 UTF-8(据我所知)。我发现的一个解决方案使用了已弃用的方法 escape() 和 unescape()。

例如,有序列:

%EF%F0%EE%E3%F0%E0%EC%EC%E8%F0%EE%E2%E0%ED%E8%E5 (программирование)

decodeURI() 和 decodeURIComponent() 方法将导致异常。

将不胜感激。

4

2 回答 2

3

据我所知,浏览器中没有内置支持带有旧字符集的百分比编码方案。你必须:

  1. 找到代表 win-1251 八位字节的 %-escapes,
  2. 将 win-1251 八位字节解码为相应的字符(JS String

下面是一种方法。对于#1,我假设只有 3 个字符的大写转义需要解码,而字符串的其余部分已经是 ASCII,所以我只使用它。inputStr.replace(/%([0-9A-Z]{2})/g,replacerFunction)

对于实际解码,您需要从 win-1251 八位字节到 JS 字符的映射。在下面的示例中,我使用 TextDecoder.decode() API构建映射,只是为了好玩(以防有人在尝试在 JS 中的不同字符集之间进行转换时找到这个答案)。(注意:目前还没有普遍支持——只有 Gecko/Blink 支持它)。

还有https://github.com/mathiasbynens/windows-1251,我最初想用它来回答这个问题,但结果证明手动构建解码图更容易。

var decodeMap = {};
var win1251 = new TextDecoder("windows-1251");
for (var i = 0x00; i < 0xFF; i++) {
  var hex = (i <= 0x0F ? "0" : "") +      // zero-padded
            i.toString(16).toUpperCase();
  decodeMap[hex] = win1251.decode(Uint8Array.from([i]));
}
// console.log(decodeMap);
// {"10":"\u0010", ... "40":"@","41":"A","42":"B", ... "C0":"А","C1":"Б", ...


// Decodes a windows-1251 encoded string, additionally
// encoded as an ASCII string where each non-ASCII character of the original
// windows-1251 string is encoded as %XY where XY (uppercase!) is a
// hexadecimal representation of that character's code in windows-1251.
function percentEncodedWin1251ToDOMString(str) {
  return str.replace(/%([0-9A-F]{2})/g,
    (match, hex) => decodeMap[hex]);
}

console.log(percentEncodedWin1251ToDOMString("%EF%F0%EE%E3%F0%E0%EC%EC%!%E8%F0%EE%E2%E0%ED%E8%E5a"))

于 2017-01-03T20:09:26.167 回答
2
  1. 查找字符串:“%EF%F0%EE%E3%F0%E0%EC%EC”、“%E8%F0%EE%E2%E0%ED%E8%E5”
  2. 将 "%" 替换为 ",0x": ",0xEF,0xF0,0xEE,0xE3,0xF0,0xE0,0xEC,0xEC", ",0xE8,0xF0,0xEE,0xE2,0xE0,0xED,0xE8,0xE5"
  3. 没有第一个逗号的切片: "0xEF,0xF0,0xEE,0xE3,0xF0,0xE0,0xEC,0xEC", "0xE8,0xF0,0xEE,0xE2,0xE0,0xED,0xE8,0xE5"
  4. 拆分成一个字符串数组: ["0xEF","0xF0","0xEE","0xE3","0xF0","0xE0","0xEC","0xEC"], ["0xE8","0xF0", "0xEE","0xE2","0xE0","0xED","0xE8","0xE5"]
  5. 创建一个字节数组:[239,240,238,227,240,224,236,236],[232,240,238,226,224,237,232,229]
  6. 将字节解码为字符串 win-1251: "программ", "ирование" 并用它们替换
var win1251 = new TextDecoder("windows-1251"),
s = "%EF%F0%EE%E3%F0%E0%EC%EC%!%E8%F0%EE%E2%E0%ED%E8%E5a"
s = s.replace(/(?:%[0-9A-F]{2})+/g,
s => win1251.decode(new Uint8Array(
s.replace(/%/g, ",0x").slice(1).split(",")
)))
alert(s)
于 2021-10-29T12:37:58.257 回答