JavaScript——编码问题

本文内容

  • Unicode 编码
  • 本地 / Unicode
  • 本地 / UTF-8
  • 本地 / ASCII
  • 本地 / URI 编码

Unicode 编码


最近搞蜘蛛程序,经常遇到编码问题,原因有两个:一是各站点所使用的传输编码不同。我特别使用了“传输编码”这个说法,后面会解释;二是站点自己做的手脚。因为,谁也不想自己的资源,被蜘蛛搞走。网络上运行的蜘蛛实在很多。第一个问题很好解决,但是第二个问题,就有点麻烦——做手脚的手段千奇百怪。

本文之所以用 Unicode 开头,而不是 ASCII 或 UTF-8 ,是因为 Unicode 编码包含各个国家的字符(ASCII 当然在其范围),得到系统内核支持,而其他常见编码都是建立在该编码基础上的。应该从两方面认识 Unicode 编码:编码方式和其实现方式。Unicode 对各个国家的字符进行了编码,但未规定它的实现方式。Unicode 实现方式不同于其编码方式。一个字符的 Unicode 编码是确定的。但在实际存储和传输过程中,由于不同系统的设计不一定一致,对 Unicode 编码的实现方式有所不同。Unicode 的实现方式称为“Unicode 转换格式(Unicode Transformation Format,UTF)”。

实现方式的不同,体现在,比如,用多个字节表示一个汉字,存在字节顺序的问题——大端(Big-Endian,BE)和小端(Little-Endian,LE)。Mac 机是小端,而 Windows 机则是大端。若有十六进制 4E59,Mac 机认为是 594E,汉字为“奎”;而 Windows 机认为是 4E59,汉字为“乙”。再如,Unicode 是定长编码,可一个英文字母用一个字节就能表示,这就存在存储代价。实现时,如 UTF-8 把定长编码变成变长的。这就是为什么 XML 和 HTML 这样需要网络传输的把 UTF-8 作为标准字符集的主要原因。

目前通用的实现方式是 UTF-16 Big-Endian、UTF-16 Little-Endian 和 UTF-8。比如,Windows 7 的 记事本,在“另存为”可以看到四种编码方式:ANSI(即英文系统为 ASCII,中文系统为 GB2312 或 Big5),Unicode(即 UTF-16 Little-Endian)、Unicode big endian(即 UTF-16 Big-Endian)和 UTF-8。

现在,很多浏览器只能显示 UCS-2 完整字符集(Unicode 版本中的一个小子集),这部分是由于 Unicode 版本发展原因。

本地 / Unicode


你可能对“本地”有点迷惑。刚开始,我也不理解,应该是编码之间转换才对。因为本地字符有编码,那么把这个编码转换成 Unicode 编码的说法很合理。其实,所有国家字符的 Unicode 编码都是确定的,无论是你输入的是哪国语。

示例 1:

例子lizi

Unicode 十进制和十六进制编码分别为:

例子lizi
例子lizi

本地到 Unicode 转换的 JavaScript 代码如下所示:

function nativeToUnicode(str) {
    var des = [];
    for (var i = 0; i < str.length; i++)
        des.push("&#" + str.charCodeAt(i) + ";");
        //des.push("&#x" + str.charCodeAt(i).toString(16) + ";");
    return des.join("");
}

Unicode 到本地转换的 JavaScript 代码如下所示:

function unicodeToNative(str) {
    var src = str.match(/&#(\d+);/g);
    if (src != null) {
        var des = [];
        for (var i = 0; i < src.length; i++)
            des.push(String.fromCharCode(src[i].replace(/[&#;]/g, "")));
        return des.join("");
    }
    return "";
}

说明:

  • String.charCodeAt() 方法可返回指定位置的字符的 Unicode 编码。这个返回值是 0 - 65535 之间的整数。
  • String.fromCharCode() 方法可接受一个指定的 Unicode 值,然后返回一个字符串。

本地 / UTF-8


UTF-8 是 Unicode 的实现方式之一,把定长编码改成变长的,减少了存储和传输的开销。从下面示例可以看到,中文是编码,而对用一个字节就能表示的英文字符,没有变化。

示例 2:

例子lizi

UTF-8 编码为:

&#x4F8B;&#x5B50;lizi

本地转换 UTF-8 的 JavaScript 代码如下所示:

function navtiveToUTF8(str) {
    return str.replace(/[^\u0000-\u00FF]/g, function ($0) { return escape($0).replace(/(%u)(\w{4})/gi, "&#x$2;") });
}

UTF-8 转换本地的 JavaScript 代码如下所示:

function utfToNative(str) {
    return unescape(str.replace(/&#x/g, '%u').replace(/;/g, ''));
}

说明:

  • escape() 函数可对字符串进行编码,这样就可以在所有的计算机上读取该字符串。
  • unescape() 函数可对通过 escape() 编码的字符串进行解码。

本地 / ASCII


示例 3:

例子lizi

ASCII 码转换或不转换 ASCII 的编码为:

\u4f8b\u5b50lizi

\u4f8b\u5b50\u006c\u0069\u007a\u0069

本地转换 ASCII 的 JavaScript 代码如下所示:

function nativeToASCII(str, isIgnoreLetter) {
    var character = str.split("");
    var ascii = [];
    for (var i = 0; i < character.length; i++) {
        var code = Number(character[i].charCodeAt(0));
        if (!isIgnoreLetter || code > 127) {
            var charAscii = code.toString(16);
            charAscii = new String("0000").substring(charAscii.length, 4) + charAscii;
            ascii.push("\\u" + charAscii);
        }
        else {
            ascii.push(character[i]);
        }
    }
    return ascii.join("");
}

ASCII 转换本地的 JavaScript 代码如下所示:

function asciiToNative(str) {
    var character = str.split("\\u");
    var res = character[0];
    for (var i = 1; i < character.length; i++) {
        var code = character[i];
        res += String.fromCharCode(parseInt("0x" + code.substring(0, 4)));
        if (code.length > 4) {
            res += code.substring(4, code.length);
        }
    }
    return res;
}

本地 / URI 编码


URI 编码不用以上编码,它的主要是出于安全性考虑,让链接的内容不能一目了然地看到是什么,防止恶意的偷看者。下面是 cnblogs 的“找找看”检索链接,对其进行编码。

示例 4:

http://zzk.cnblogs.com/s?w=例子lizi&t=

URI 编码和组件编码分别为:

http://zzk.cnblogs.com/s?w=%E4%BE%8B%E5%AD%90lizi&t=

http%3A%2F%2Fzzk.cnblogs.com%2Fs%3Fw%3D%E4%BE%8B%E5%AD%90lizi%26t%3D

说明:

  • encodeURI() 函数可把字符串作为 URI 进行编码。
  • decodeURI() 函数可对 encodeURI() 函数编码过的 URI 进行解码。
  • encodeURIComponent() 函数可把字符串作为 URI 组件进行编码。
  • decodeURIComponent() 函数可对 encodeURIComponent() 函数编码的 URI 进行解码。

下载 Demo

posted @ 2012-12-09 22:23  船长&CAP  阅读(628)  评论(7编辑  收藏  举报
免费流量统计软件