如何使用javascript将特殊的UTF-8字符转换为其iso-8859-1等效字符?

如何使用javascript将特殊的UTF-8字符转换为其iso-8859-1等效字符?,javascript,jquery,character-encoding,Javascript,Jquery,Character Encoding,我正在制作一个javascript应用程序,它使用jquery检索.json文件,并将数据注入嵌入其中的网页 .json文件使用UTF-8编码,并包含重音字符,如é、ö和å 问题是我无法控制将要使用该应用程序的页面上的字符集 一些将使用UTF-8,但其他将使用iso-8859-1字符集。这当然会篡改.json文件中的特殊字符 如何使用javascript将特殊的UTF-8字符转换为其iso-8859-1等效字符 问题在于,一旦提供了页面,内容将采用content type meta标记中描述的编

我正在制作一个javascript应用程序,它使用jquery检索
.json
文件,并将数据注入嵌入其中的网页

.json
文件使用UTF-8编码,并包含重音字符,如é、ö和å

问题是我无法控制将要使用该应用程序的页面上的字符集

一些将使用UTF-8,但其他将使用iso-8859-1字符集。这当然会篡改
.json
文件中的特殊字符


如何使用javascript将特殊的UTF-8字符转换为其iso-8859-1等效字符

问题在于,一旦提供了页面,内容将采用content type meta标记中描述的编码。“错误”编码的内容已被篡改


在提供页面之前,最好在服务器上执行此操作。或者正如我所说的:UTF-8端到端或死。

实际上,所有内容通常在内部以某种Unicode形式存储,但我们不必深入讨论。我假设您得到的是标志性的“Ã¥ÃÃè”类型字符串,因为您使用ISO-8859作为字符编码。有一个技巧可以用来转换这些字符。用于编码和解码查询字符串的
escape
unescape
函数是为ISO字符定义的,而更新的
encodeURIComponent
decode uricomponent
函数也是为UTF8字符定义的


escape
将扩展ISO-8859-1字符(UTF代码点U+0080-U+00ff)编码为
%xx
(两位十六进制),而将UTF代码点U+0100及以上编码为
%uxxx
%U
后接四位十六进制)。例如,
escape(“å”)=%E5”
escape(“あ") == "%u3042“

encodeURIComponent
percent将扩展字符编码为UTF8字节序列。例如,
encodeURIComponent(“å”)==%C3%A5”
encodeURIComponent(“あ") == "%E3%81%82“

因此,您可以:

fixedstring = decodeURIComponent(escape(utfstring));
例如,一个编码错误的字符“å”变为“Ô。该命令执行
escape(“Ô)=%C3%A5”
,这是编码为单个字节的两个不正确的ISO字符。然后
decodeURIComponent(%C3%A5”)==“å”
,其中两个编码字节被解释为UTF8序列

如果出于某种原因需要进行相反的操作,也可以:

utfstring = unescape(encodeURIComponent(originalstring));
有没有办法区分坏的UTF8字符串和ISO字符串?事实证明是有办法的。如果给定的编码序列格式不正确,上面使用的decodeURIComponent函数将抛出错误。我们可以用它很有可能检测字符串是UTF8还是ISO

var fixedstring;

try{
    // If the string is UTF-8, this will work and not throw an error.
    fixedstring=decodeURIComponent(escape(badstring));
}catch(e){
    // If it isn't, an error will be thrown, and we can assume that we have an ISO string.
    fixedstring=badstring;
}

在内部,Javascript字符串都是Unicode(实际上是UCS-2,UTF-16的子集)

如果要通过AJAX单独检索JSON文件,则只需确保JSON文件具有正确的内容类型和字符集:
Content-Type:application/JSON;charset=“utf-8”
)。如果这样做,那么当您访问反序列化对象时,jQuery应该已经正确地解释了它们


您可以发布一个用于检索JSON对象的代码示例吗?

您应该在页面上方添加这一行

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

由于这个问题,关于如何从ISO-8859-1转换为UTF-8的讨论已经结束,我将在这里发布我的解决方案

问题是,当您试图通过使用XMLHttpRequest获取任何内容时,如果XMLHttpRequest.responseType为“text”或空,则XMLHttpRequest.response将转换为DOMString,这就是问题所在。之后,几乎不可能可靠地使用该字符串

现在,如果来自服务器的内容是ISO-8859-1,则必须强制响应类型为“”,然后将其转换为DOMSTring。例如:

var ajax = new XMLHttpRequest();
ajax.open('GET', url, true);
ajax.responseType = 'blob';
ajax.onreadystatechange = function(){
    ...
    if(ajax.responseType === 'blob'){
        // Convert the blob to a string
        var reader = new window.FileReader();
        reader.addEventListener('loadend', function() {
           // For ISO-8859-1 there's no further conversion required
           Promise.resolve(reader.result);
        });
        reader.readAsBinaryString(ajax.response);
    }
}

看起来readAsBinaryString上的魔法正在发生,所以也许有人可以解释一下为什么它会起作用。

有一些库可以在Javascript中进行字符集转换。但是如果您想要一些简单的东西,这个函数可以大致满足您的需要:

function stringToBytes(text) {
  const length = text.length;
  const result = new Uint8Array(length);
  for (let i = 0; i < length; i++) {
    const code = text.charCodeAt(i);
    const byte = code > 255 ? 32 : code;
    result[i] = byte;
  }
  return result;
}

现在,请记住,有些应用程序确实接受UTF-8编码,但除非您预先添加一个BOM字符,否则它们无法猜出编码,如前所述。

我已经在我自己的问题的答案中引用了您的答案:@nitro:javascript是否将每个UTF-8字符都视为ISO拉丁语?
escape
编码扩展的ISO-8859-1字符rs(UTF代码点U+0080-U+00ff)为
%xx
(两位十六进制),而它将UTF代码点U+0100及以上编码为
%uxxx
%U
后接四位十六进制)。例如,
转义(“å”)=%E5
转义(“あ") == "%u3042“
encodeURIComponent
percent将扩展字符编码为UTF8字节序列。例如,
encodeURIComponent(“å”)==%C3%A5”
encodeURIComponent(“あ") == "%E3%81%82“
。我希望这能澄清所有问题。@nitro2k01:你的建议有误:
未捕获的URIError:URI格式错误的
转义函数将被弃用!!虽然我的页眉已经在utf-8上显示了它,但我必须将其转换为ISO拉丁语进行进一步加密。这并不能回答问题!它与此无关,都已设置仅设置内容类型或字符集:jQuery以完全相同的方式解释所提供的json。可能是因为规范()规定
json文本应使用Unicode编码。默认编码为UTF-8
。因此,将标题设置为
content-type:application/json;charset=“iso-8859-1”
对变量中的文本进行json编码后,从iso-8859-1编码的文件中获取文本,并通过ajax将其发送到iso-8859-1编码的html页面,产生与不指定任何内容相同的结果:th
const originalString = 'ååå';
const bytes = stringToBytes(originalString);
const blob = new Blob([bytes.buffer], { type: 'text/plain; charset=ISO-8859-1' });