我正在制作一个 javascript 应用程序,它.json
使用 jquery检索文件并将数据注入它嵌入的网页中。
这些.json
文件使用 UTF-8 编码并包含重音字符,如 é、ö 和 å。
问题是我无法控制将要使用该应用程序的页面上的字符集。
有些将使用 UTF-8,但其他将使用 iso-8859-1 字符集。这当然会使.json
文件中的特殊字符乱码。
如何使用 javascript 将特殊的 UTF-8 字符转换为等效的 iso-8859-1?
我正在制作一个 javascript 应用程序,它.json
使用 jquery检索文件并将数据注入它嵌入的网页中。
这些.json
文件使用 UTF-8 编码并包含重音字符,如 é、ö 和 å。
问题是我无法控制将要使用该应用程序的页面上的字符集。
有些将使用 UTF-8,但其他将使用 iso-8859-1 字符集。这当然会使.json
文件中的特殊字符乱码。
如何使用 javascript 将特殊的 UTF-8 字符转换为等效的 iso-8859-1?
实际上,所有内容通常都在内部存储为某种 Unicode,但我们不要深入研究。我假设您得到标志性的“åäö”类型字符串,因为您使用 ISO-8859 作为字符编码。您可以使用一个技巧来转换这些字符。用于编码和解码查询字符串的escape
和unescape
函数是为 ISO 字符定义的,而较新的encodeURIComponent
和decodeURIComponent
执行相同操作的函数是为 UTF8 字符定义的。
escape
将扩展的 ISO-8859-1 字符(UTF 代码点 U+0080-U+00ff)%xx
编码为(两位十六进制),而将 UTF 代码点 U+0100 及以上编码为%uxxxx
(%u
后跟四位十六进制。)例如,escape("å") == "%E5"
和escape("あ") == "%u3042"
。
encodeURIComponent
将扩展字符百分比编码为 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;
}
问题在于,一旦提供了页面,内容将采用内容类型元标记中描述的编码。“错误”编码的内容已经是乱码。
您最好在提供页面之前在服务器上执行此操作。或者正如我所知:UTF-8 end-to-end or die。
由于问题如何从ISO-8859-1转换为UTF-8,因为这一次我要在这里发布我的解决方案的关闭。
问题是当您尝试使用 XMLHttpRequest 获取任何内容时,如果 XMLHttpRequest.responseType 为“文本”或为空,则 XMLHttpRequest.response 将转换为 DOMString 并且这就是问题。之后,几乎不可能可靠地使用该字符串。
现在,如果来自服务器的内容是 ISO-8859-1,您必须强制响应类型为“ Blob ”,然后将其转换为 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 字符串都是 Unicode(实际上是 UCS-2,UTF-16 的子集)。
如果您通过 AJAX 单独检索 JSON 文件,那么您只需要确保使用正确的 Content-Type 和字符集提供 JSON 文件:) Content-Type: application/json; charset="utf-8"
。如果你这样做了,当你访问反序列化对象时,jQuery 应该已经正确地解释了它们。
您能否发布一个用于检索 JSON 对象的代码示例?
有一些库可以在 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;
}
如果要将生成的字节数组转换为 Blob,可以执行以下操作:
const originalString = 'ååå';
const bytes = stringToBytes(originalString);
const blob = new Blob([bytes.buffer], { type: 'text/plain; charset=ISO-8859-1' });
现在,请记住,有些应用程序确实接受UTF-8编码,但除非你在前面加上一个BOM字符,他们无法猜测的编码,解释在这里。