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

yrdbyhpb  于 2023-04-11  发布在  jQuery
关注(0)|答案(7)|浏览(325)

我正在做一个javascript应用程序,它可以用jquery检索.json文件,并将数据注入到嵌入的网页中。
.json文件使用UTF-8编码,并包含é、ö和å等重音字符。
问题是,我不能控制将要使用该应用程序的页面上的字符集。
有些将使用UTF-8,但其他将使用iso-8859-1字符集。这当然会混淆.json文件中的特殊字符。
如何使用javascript将特殊的UTF-8字符转换为它们的iso-8859-1等效字符?

x8diyxa7

x8diyxa71#

实际上,所有内容通常都在内部存储为某种Unicode,但我们不讨论这个问题。我假设你得到的是标志性的“¥ ääö”类型字符串,因为你使用ISO-8859作为字符编码。有一个技巧可以转换这些字符。用于编码和解码查询字符串的escapeunescape函数是为ISO字符定义的,而较新的encodeURIComponentdecodeURIComponent做同样的事情,是为UTF8字符定义的。
escape将扩展ISO-8859-1字符(UTF代码点U+0080-U+00 ff)编码为%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;
}
zynd9foi

zynd9foi2#

问题是,一旦页面被提供,内容将使用content-type meta标记中描述的编码。“错误”编码的内容已经乱码了。
你最好在服务器上提供页面之前做这个。或者就像我一直知道的那样:*UTF-8端到端或死 *。

gv8xihay

gv8xihay3#

由于question关于如何从ISO-8859-1转换为UTF-8是关闭的,因为这一个我将在这里张贴我的解决方案。
问题是,当你尝试使用XMLHttpRequest获取任何东西时,如果XMLHttpRequest.responseType是“text”或空的,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 上发生,所以也许有人可以解释一下为什么它会起作用。

wpx232ag

wpx232ag4#

在内部,Javascript字符串都是Unicode(实际上是UCS-2,UTF-16的子集)。
如果您通过 AJAX 单独检索JSON文件,则只需确保JSON文件使用正确的Content-Type和charset:如果你这样做了,那么在你访问反序列化的对象时,jQuery应该已经正确地解释了它们。
你能发布一个你用来检索JSON对象的代码的例子吗?

uemypmqf

uemypmqf5#

在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字符,如here所解释的那样。

6kkfgxo0

6kkfgxo06#

由于escape已被弃用(实际上对我不起作用),我使用了一个小型库进行编码。我使用了一个名为iso-8859-15的库。请注意,ISO-8859-15与ISO-8859-1只有几个字符不同(比较),并且很可能您的输入实际上是ISO-8859-15而不是ISO-8859-1。

import {encode} from 'iso-8859-15';

const encodedBytes = new Uint8Array(encode(unicodeString))
const blob = new Blob([encodedBytes])
tf7tbtn2

tf7tbtn27#

你应该在你的页面上面加上这一行

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

相关问题