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

时间:2010-04-07 22:59:54

标签: javascript unicode urlencode encode utf-8

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

例如对于“%96”,它应该是 - ,我在尝试解码时遇到错误:

decodeURIComponent("%96");
URIError: URI malformed

如果我尝试编码“ - ”我实际得到:

encodeURIComponent("–");
"%E2%80%93"

我在互联网上搜索过,我看到了this page,它分别提到了使用escape和unescape与decodeURIComponent和encodeURIComponent。这似乎没有帮助,因为%96不会显示为“ - ”,无论我尝试什么,这当然不会起作用:

decodeURIComponent(escape("%96));
"%96"

不是很有帮助。

如何使用JavaScript将“%96”变成“ - ”(没有为我可能遇到的每个可能的unicode字符硬编码地图)?

3 个答案:

答案 0 :(得分:4)

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

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

你引用的角色是U + 2013,一个短划线。您引用的页面如何从十六进制0x96(十进制150)获得一个en-dash?他们显然没有采用UTF-8编码,这是标准。它们不假设ASCII,不包含此字符。它们甚至不假设ISO-8859-1,这是一种标准编码,每个字符使用一个字节。事实证明他们正在假设特殊的Windows 1252代码页。也就是说,您尝试解码的URI假定用户在Windows计算机上,更糟糕的是,在Windows机器上使用英语(或其他一些西方语言)。

简而言之,您使用的表格很糟糕。它已过时并假定用户使用的是英文Windows系统。对非ASCII值进行编码的最新且正确的方法是将它们转换为UTF-8,然后使用%XX对每个八位字节进行编码。这就是为什么当你试图对角色进行编码时你得到%E2%80%93,这就是decodeURIComponent()所期待的。您正在使用的URI未正确编码。如果您没有其他选择,您可以猜测URI是使用Windows 1252,自己转换字节,然后使用Windows 1252表来找出想要的Unicode值。但这有风险---你怎么知道哪个URI使用哪个表?这就是每个人都选择UTF-8的原因。如果可能的话,告诉谁给你这些URI以正确编码它们。

答案 1 :(得分:2)

发布社区wiki条目,因为它来自Carl Henderson的“构建可扩展网站”。该书说,重现这些例子的重要部分是可以的。您可以使用它创建“ - ”的特殊情况。

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);
}

答案 2 :(得分:1)

请参阅this question,具体为this answer

  

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

我怀疑“ - ”是其中一个字符,因为Ascii table中的0x96是û