001.
我们已经认识了统一字符集UCS的编码形式,所以知道,UTF-8采用一个或多个8比特的编码形式;UTF-16采用一个或者两个16比特的编码形式;UTF-32采用32比特的编码形式。
但正如我们已经说过的,UTF-16和UTF-32字符编码在保存到文件或者在计算机设备之间传输时,需要拆分成字节,并且必然涉及到字节序的问题。在所有计算机系统中,一个字节的长度至少是8个比特,所以可将8比特视同为一个字节。
在保存和传输统一字符集UCS的字符时,每个UTF-16或者UTF-32字符编码都要拆分成一个或者多个8比特,或者说拆分为一个或者多个字节。采用低端字节序和采用高端字节序的计算机系统是不一样的,具有不同的体系结构,而不同的体系结构决定了拆分之后哪个字节在前,哪个字节在后,当然也可以人为指定字节的顺序。
从现在开始,术语“编码方案”是指将一个字符的编码拆解为何种顺序的8比特(字节)序列。UTF-8编码方案不存在字节序的问题,因为它本身就是由一个或者多个8比特组成。尽管如此,也将其归为一种编码方案。因此,统一字符集UCS一共有7种编码方案,分别是UTF-8、UTF-16BE、UTF-16LE、UTF-16、UTF-32BE、UTF-32LE、UTF-32。
UTF-16BE编码方案的特点是UTF-16编码的高8比特在前,低8比特在后。
UTF-16LE编码方案的特点是UTF-16编码的低8比特在前,高8比特在后;
如果没有明确指定,UTF-16编码方案默认等同于UTF-16BE。
UTF-32BE编码方案的特点是先将UTF-32编码的高16位拆分成两个8比特,再将低16位拆分成两个8比特。每次拆分时,高8比特在前,低8比特在后;
UTF-32LE编码方案的特点是先将UTF-32编码的低16位拆分成两个8比特,再将高16位拆分成两个8比特。每次拆分时,低8比特在前,高8比特在后;
如果没有明确指定,UTF-32编码方案默认等同于UTF-32BE。
002.
文本的接收方可能知道正确的字节顺序,这最好不过了,但也可能不知道。为了让文本的接收方知道正确的字节顺序,需要想办法,而标准的方法是在文本的开头添加一个特殊的字符。
在统一字符集UCS里,有一个特殊的字符,它的代码点是U+FEFF。最初的时候,它被定义为零宽度不间断空格。什么是零宽度不间断空格?它就是空格字符,但宽度为零,显示不出来。如果它夹在两个有形状的字符中间,比如夹在字符A和B中间,那么显示的时候是显示不出来的,你会发现A和B是挨着的,就象它们中间并没有其它字符。这个特点使得零宽度不间断空格字符非常有用,比如可以干扰文本处理设备但不影响人类的阅读体验,以及防止文本过滤,等等。到了后来,这个字符只能放在一个字节序列的开始,用来作为字节序的标记,byte-order mark,简称BOM。
003.
前面说过,UTF-8编码方案不存在字节序的问题,因为它本身就是由一个或者多个8比特组成。如果需要,可以在要保存和发送的文本前添加一个代码点为U+FEFF的字符作为标志或者说签名,以表明这个文本的序列是采用UTF-8编码的。如此一来,在8比特序列的一开始就会是EF BB BF,这正是字符U+FEFF的UTF-8编码。
004.
如果需要,可以在UTF-16BE编码序列的最前面添加两个8比特FE FF,以表明这些文本是采用UTF-16BE编码的,这实际上相当于在原始文本的前面添加了一个代码点为U+FEFF的字符。当这个字符用UTF-16BE编码方案保存或者发送时,它对应的8比特序列正是FE FF。
在字符的读取或者接收方,如果读取或者接收的依次是FE FF,它就知道,这些文本采用的编码方案是UTF-16BE。
005.
如果需要,可以在UTF-16LE编码序列的最前面添加两个8比特FF FE,以表明这些文本是采用UTF-16LE编码的,这实际上相当于在原始文本的前面添加了一个代码点为U+FEFF的字符。当这个字符用UTF-16LE编码方案保存或者发送时,它对应的8比特序列正是FF FE。
在字符的读取或者接收方,如果读取或者接收的依次是FF FE,它就知道,这些文本采用的编码方案是UTF-16LE。
006.
前面说过,UTF-16编码方案可能等同于UTF-16BE,也可能等同于UTF-16LE。如果有签名FE FF,意味着它等同于UTF-16BE;如果有签名FF FE,意味着它等同于UTF-16LE;如果没有签名,则它等同于UTF-16BE。
007.
如果需要,可以在UTF-32BE编码序列的最前面添加四个8比特00 00 FE FF,以表明这些文本是采用UTF-32BE编码的,这实际上相当于在原始文本的前面添加了一个代码点为U+FEFF的字符。当这个字符用UTF-32BE编码方案保存或者发送时,它对应的8比特序列正是00 00 FE FF。
在字符的读取或者接收方,如果读取或者接收的依次是00 00 FE FF,它就知道,这些文本采用的编码方案是UTF-32BE。
008.
如果需要,可以在UTF-32LE编码序列的最前面添加四个8比特FF FE 00 00,以表明这些文本是采用UTF-32LE编码的,这实际上相当于在原始文本的前面添加了一个代码点为U+FEFF的字符。当这个字符用UTF-32LE编码方案保存或者发送时,它对应的8比特序列正是FF FE 00 00。
在字符的读取或者接收方,如果读取或者接收的依次是FF FE 00 00,它就知道,这些文本采用的编码方案是UTF-32LE。
009.
前面说过,UTF-32编码方案可能等同于UTF-32BE,也可能等同于UTF-32LE。如果有签名00 00 FE FF,意味着它等同于UTF-32BE;如果有签名FF FE 00 00,意味着它等同于UTF-32LE;如果没有签名,则它等同于UTF-32BE。
表7-2列举几个例子以说明在不同的编码方案下,字符的UTF-16编码是如何被串化的,这张表的出处和表7-1相同。 表7-2 UTF-16编码在不同编码方案下的字节序列 | | | | | | | | | FE FF 00 4D (注:实际对应UTF-16BE) FF FE 4D 00 (注:实际对应UTF-16LE) 00 4D (注:实际对应UTF-16BE) | | | | | | | FE FF 04 30 (注:实际对应UTF-16BE) FF FE 30 04 (注:实际对应UTF-16LE) 04 30 (注:实际对应UTF-16BE) | | | | | | | FE FF 4E 8C (注:实际对应UTF-16BE) FF FE 8C 4E (注:实际对应UTF-16LE) 4E 8C (注:实际对应UTF-16BE) | | | D8 00 DF 02或者FE FF D8 00 DF 02 | | 00 D8 02 DF或者FF FE 00 D8 02 DF | | FE FF D8 00 DF 02 (注:实际对应UTF-16BE) FF FE 00 D8 02 DF (注:实际对应UTF-16LE) D8 00 DF 02 (注:实际对应UTF-16BE) |
同样地,如果UTF-32对应着UTF-32LE,则需要在字符编码之前添加字节序列FF FE 00 00;如果UTF-32对应着UTF-32BE,则需要在字符编码之前添加字节序列00 00 FE FF。表7-3列举几个例子以表明在不同的编码方案下,字符的UTF-32编码是如何被串化的,这张表的出处和表7-1相同。 表7-3 UTF-32编码在不同编码方案下的字节序列 | | | | | 00 00 00 4D或者00 00 FE FF 00 00 00 4D | | 4D 00 00 00或者FF FE 00 00 4D 00 00 00 | | 00 00 FE FF 00 00 00 4D (注:实际对应UTF-32BE) FF FE 00 00 4D 00 00 00 (注:实际对应UTF-32LE) 00 00 00 4D (注:实际对应UTF-32BE,无BOM) | | | 00 00 04 30或者00 00 FE FF 00 00 04 30 | | 30 04 00 00或者FF FE 00 00 30 04 00 00 | | 00 00 FE FF 00 00 04 30 (注:实际对应UTF-32BE) FF FE 00 00 30 04 00 00 (注:实际对应UTF-32LE) 00 00 04 30 (注:实际对应UTF-32BE,无BOM) | | | 00 00 4E 8C或者00 00 FE FF 00 00 4E 8C | | 8C 4E 00 00或者FF FE 00 00 8C 4E 00 00 | | 00 00 FE FF 00 00 4E 8C (注:实际对应UTF-32BE) FF FE 00 00 8C 4E 00 00 (注:实际对应UTF-32LE) 00 00 4E 8C (注:实际对应UTF-32BE,无BOM) | | | 00 01 03 02或者00 00 FE FF 00 01 03 02 | | 02 03 01 00或者FF FE 00 00 02 03 01 00 | | 00 00 FE FF 00 01 03 02 (注:实际对应UTF-32BE) FF FE 00 00 02 03 01 00 (注:实际对应UTF-32LE) 00 01 03 02 (注:实际对应UTF-32BE,无BOM) |
相对于带有LE和BE后缀的编码方案而言,UTF-16和UTF-32编码方案的BOM不是必需的,如果仅用于内部处理,可以不使用;但如果要将文本保存到磁盘文件,或者在网络和计算机系统之间传送,则通常需要在开头放置BOM。
|