万字长文讲解编码知识,看这文就够了!| 原力计划( 五 )


  • 其它字符用多个字节来编码(假设用N个字节),多字节编码需满足:第一个字节的前N位都为1,第N+1位为0,后面N-1 个字节的前两位都为10,这N个字节中其余位全部用来存储Unicode中的码位值 。

  • 万字长文讲解编码知识,看这文就够了!| 原力计划

    文章插图
    现如今UTF-8 是互联网上使用最广的一种 Unicode 的实现方式,是其他两种无可比拟的 。
    (5)UTF的字节序和BOM
    字节序就要先补充一点知识:
    码元(code unit):是能用于处理或交换编码文本的最小比特组合 。它代表某种编码中最小的可用来识别一个合法字符的最小字节数序列 。
    • UTF-8使用变长的字节序列来表示字符;某个字符(对应一个码点)可能使用1-4个字节才能表示;在UTF-8中一个字符最小可能一个字节,所以我们规定1个字节就是一个码元;
    • UTF-16使用也变长字节序列来表示字符;某个字符(对应一个码点)可能使用2个或者4个字符来表示;因为2个字节序列是最小的能够识别一个码点的单位,同理我们规定2个字节就是一个码元;
    • UTF-32使用定长的4个字节表示一个字符;一个字符(对应一个码点)使用4个字符来表示,这样4个字节就是一个码元 。
    简单来说,就是“码点”经过映射后得到的二进制串的转换格式单位称之为“码元” 。“码点”就是一串二进制数,“码元”就是切分这个二进制数的方法 。这些编码每次处理一个码元,你可以把它理解为UTF-8每次读码点的8位,UTF-16每次读码点的16位,UTF-32每次读码点的32位, 。当然这也是为什么叫这些叫Unicode转换格式的原因 。处理的是同一个字符集,但是处理方式不同 。
    万字长文讲解编码知识,看这文就够了!| 原力计划

    文章插图
    字节序
    UTF-8一次一个UTF-8码元,即处理一个字节,没有字节序的问题 。UTF-16一次处理一个UTF-16码元,对应两个字节,UTF-32一次一个UTF-32码元,对应处理四个字节,所以这就要考虑到一个字节序问题 。
    以UTF-16w为例,在解释一个UTF-16编码文本前,首先要弄清楚每个编码单元的字节序 。例如收到一个“奎”的Unicode编码是594E,“乙”的Unicode编码是4E59 。
    如果我们收到UTF-16字节流“594E”,那么这是“奎”还是“乙”?这就考虑大小端问题,所以UTF-16编码包括三种:UTF-16BE(Big Endian),UTF-16LE(Little Endian)、UTF-16(类似的名称UCS-2BE和UCS-2LE用于显示UCS-2的版本 。)
    UTF-16BE和UTF-16LE好理解,直接指定了字节序(大小端),但是UTF-16怎么处理呢?
    Unicode规范中推荐的标记字节顺序的方法是BOM 。BOM不是“Bill Of Material”的BOM表,而是Byte Order Mark 。BOM是一个有点小聪明的想法:
    在UCS编码中有一个叫做"ZERO WIDTH NO-BREAKSPACE"的字符,它的编码是FEFF 。而FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中 。UCS规范建议我们在传输字节流前,先传输字符"ZERO WIDTH NO-BREAK SPACE" 。这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little-Endian的 。
    同样的类比,UTF-32也是这样的 。有UTF-32BE、UTF-32LE、UTF-32 。前面UTF-32BE和UTF-32LE直接指定了字节序(大小端),后面的UTF-32也是靠BOM 。
    UTF-8不需要BOM来表明字节顺序,但可以用BOM来表明编码方式 。字符"ZERO WIDTH NO-BREAKSPACE"的UTF-8编码是EF BB BF(读者可以用我们前面介绍的编码方法验证一下) 。所以如果接收者收到以EF BB BF开头的字节流,就知道这是UTF-8编码了 。
    windows就是使用BOM来标记文本文件的编码方式的 。它就建议所有的 Unicode 文件应该以 ZERO WIDTH NOBREAK SPACE(U+FEFF)字符开头 。这作为一个“特征符”或“字节顺序标记(byte-ordermark,BOM)”来识别文件中使用的编码和字节顺序 。所以用Windows自带的记事本将文件保存为UTF-8编码的时候,记事本会自动在文件开头插入BOM(虽然BOM对UTF-8来说并不是必须的) 。
    但也有一些系统或程序不支持BOM,因此带有BOM的Unicode文件有时会带来一些问题 。比如JDK1.5以及之前的Reader都不能处理带有BOM的UTF-8编码的文件,解析这种格式的xml文件时,会抛出异常:Content is not allowed inprolog 。
    linux/UNIX 并没有使用 BOM,因为它会破坏现有的 ASCII 文件的语法约定 。所以一般我们不建议用Windows自带的记事本编辑UTF-8文件就是这样 。
    万字长文讲解编码知识,看这文就够了!| 原力计划


    推荐阅读