JavaScript中的Unicode和URI编码、解码和转义

JavaScript中的Unicode和URI编码、解码和转义,javascript,unicode,urlencode,encode,utf-8,Javascript,Unicode,Urlencode,Encode,Utf 8,如果你看这个,它有一个Unicode字符的转义序列列表,实际上对我不起作用 例如,对于“%96”,它应该是–,我在尝试解码时出错: decodeURIComponent("%96"); URIError: URI malformed 如果我尝试编码“–”,我实际上得到: encodeURIComponent("–"); "%E2%80%93" 我在互联网上搜索了一下,我看到了,其中提到使用escape和unescape分别与decodeURIComponent和encodeURICompon

如果你看这个,它有一个Unicode字符的转义序列列表,实际上对我不起作用

例如,对于“%96”,它应该是–,我在尝试解码时出错:

decodeURIComponent("%96");
URIError: URI malformed
如果我尝试编码“–”,我实际上得到:

encodeURIComponent("–");
"%E2%80%93"
我在互联网上搜索了一下,我看到了,其中提到使用escape和unescape分别与decodeURIComponent和encodeURIComponent一起使用。这似乎没有什么帮助,因为无论我做什么尝试,%96都不会显示为“–”,这当然行不通:

decodeURIComponent(escape("%96));
"%96"
不是很有帮助

我怎样才能使“%96”成为一个带有JavaScript的“–”(而不必为我可能遇到的每个可能的unicode字符硬编码映射)

具体见:

有一种特殊的“%unnn”格式 编码Unicode UTF-16码点, 而不是编码UTF-8字节


我怀疑“–”是其中一个字符,因为它来自卡尔·亨德森(Carl Henderson)的“构建可伸缩的网站”,所以在isā

中以社区维基条目的形式发布0x96。不过,这本书说,可以复制示例的重要部分。您可以使用它为“-”创建一个特例

函数escape\u utf8(数据){
如果(数据=''| |数据==null){
返回“”;
}
data=data.toString();
var缓冲区=“”;
对于(变量i=0;i 0x10000){
//4字节
bs[0]=0xF0 |((c&0x1C0000)>>>18);
bs[1]=0x80 |((c&0x3F000)>>>12);
bs[2]=0x80 |((c&0xFC0)>>>6);
bs[3]=0x80 |(c&0x3F);
}否则,如果(c>0x800){
//3字节
bs[0]=0xE0 |((c&0xF000)>>>12);
bs[1]=0x80 |((c&0xFC0)>>>6);
bs[2]=0x80 |(c&0x3F);
}否则,如果(c>0x80){
//2字节
bs[0]=0xC0 |((c&0x7C0)>>>6);
bs[1]=0x80 |(c&0x3F);
}否则{
//1字节
bs[0]=c;
}
对于(var j=0;j>>4)
+半字节到十六进制(b&0x0F);缓冲区+='%'+hex;
}
}
返回缓冲区;
}
函数半字节到十六进制(半字节){
var chars='0123456789ABCDEF';
返回字符(半字节);
}

URI中的序列
%XX
编码一个“八位字节”,即八位字节。这就提出了一个问题,即解码字节指的是什么Unicode字符。如果我的记忆正确的话,在旧版本的URI规范中,并没有很好地定义假定的字符集。在URI规范的更高版本中,建议将UTF-8作为默认编码字符集。也就是说,要解码一个字节序列,您需要解码每个
%XX
序列,然后使用UTF-8字符集将结果字节转换为字符串

这解释了为什么
%96
无法解码。十六进制0x96值不是有效的UTF-8序列。因为它超出了ASCII,所以在它前面需要一个特殊的修饰符字节来表示扩展字符。(有关更多详细信息,请参阅UTF-8规范。)JavaScript
encodeURIComponent()
decodeURIComponent()
方法都采用UTF-8(正如它们应该的那样),因此我不希望
%96
正确解码

您引用的字符是U+2013,一个en破折号。你引用的页面究竟是如何从十六进制0x96(十进制150)中得到一个破折号的?他们显然没有采用UTF-8编码,这是标准。它们不采用ASCII,ASCII不包含此字符。他们甚至没有假设,这是一种标准编码,每个字符使用一个字节。事实证明,他们假设的是特殊的代码页。也就是说,您试图解码的URI假设用户在Windows机器上,更糟糕的是,在英语(或其他几种西方语言之一)的Windows机器上


简而言之,你用的桌子不好。它已过时,并假定用户使用的是英文Windows系统。对非ASCII值进行编码的最新正确方法是将其转换为UTF-8,然后使用
%XX
对每个八位字节进行编码。这就是为什么在尝试对字符编码时得到了
%E2%80%93
,而这正是
decodeURIComponent()
所期望的。您正在使用的URI编码不正确。如果没有其他选择,您可以猜测URI使用的是Windows 1252,自己转换字节,然后使用Windows 1252表找出Unicode值的用途。但这很危险——您如何知道哪个URI使用哪个表?这就是为什么每个人都选择UTF-8。如果可能,请告诉给您这些URI的人正确编码它们。

我不确定这有什么帮助,因为我正在尝试将%nn格式转换为unicode,而不是相反。我想您可以在使用decodeURIComponent在javascript中对其进行解码之前,将“-”替换为“%E2%80%93”,但它可能会有副作用,所以我不知道。不幸的是,我无法控制espace进程,它是一个野生的字符串。我只需要能够在所有情况下处理“%nn”格式。如果代码是单个的“%nn”“代码您确定源数据是用Unicode编码的,而不是ASCII/Latin-1等吗?decode/encodeUri组件可能使用当前页面的编码,我假设在您的示例中是UTF-8。如果是这样的话,这可能是一个黑客攻击,但您可以使用另一个IFrame,使用不同的编码与父级或类似的方式进行通信,作为最后的手段。或者,您可以使用从另一个编码到Unicode的表,并通过拆分“%”字符或类似的内容进行解码,然后自己处理。只是一些建议:-)escape(“–”)创建“%u2013”。这仍然不能解释我遇到%96时如何处理%96
function escape_utf8(data) {
        if (data == '' || data == null){
               return '';
        }
       data = data.toString();
       var buffer = '';
       for(var i=0; i<data.length; i++){
               var c = data.charCodeAt(i);
               var bs = new Array();
              if (c > 0x10000){
                       // 4 bytes
                       bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
                       bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
                       bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
                   bs[3] = 0x80 | (c & 0x3F);
               }else if (c > 0x800){
                        // 3 bytes
                        bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
                        bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
                       bs[2] = 0x80 | (c & 0x3F);
             }else if (c > 0x80){
                      // 2 bytes
                       bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
                      bs[1] = 0x80 | (c & 0x3F);
               }else{
                       // 1 byte
                    bs[0] = c;
              }
             for(var j=0; j<bs.length; j++){
                      var b = bs[j];
                       var hex = nibble_to_hex((b & 0xF0) >>> 4) 
                      + nibble_to_hex(b &0x0F);buffer += '%'+hex;
              }
    }
    return buffer;
}
function nibble_to_hex(nibble){
        var chars = '0123456789ABCDEF';
        return chars.charAt(nibble);
}