Unicode:由Unicode Consortium制定的编码方式。从2.0版本开始采用17个字符平面,码表地址从0到0x10FFFF,即21位编码。

UCS:即Universal Character Set,由ISO制定的ISO/IEC 10646标准指定的编码方式。采用4字节编码。为和Unicode达成一致,将编码上限封顶为0x10FFFF。

Note. Unicode Consortium和ISO 10646制定者原本是两伙人,后于1991年开始合作,此后逐渐趋于一致,因而往往我们对他们在码表等问题上不加区分。

编码方式:

  • UCS-4,fixed-length encoding,4字节编码,对UCS的最朴素的编码
  • UCS-2,fixed-length encoding,2字节编码,只能表示0~0xFFFF中的字符,相当于UCS-4低16位
  • UTF-32,fixed-length encoding,4字节编码,但限定在0~0x10FFFF区段。原本是UCS-4的子集。在ISO将码表封顶为0x10FFFF后,与UCS-4意义基本等同。
  • UTF-16,variable-length encoding,对0~0xFFFF(不含0xD800~0xDFFF)区段的编码与UCS-2等同(2字节),对0x10000~0x10FFFF区段的编码利用0xD800~0xDFFF区段生成surrogate pairs(4字节)。无法对0xD800~0xDFFF编码(这一段不是valid characters,所以基本没什么影响)。
  • UTF-8,variable-length encoding,将码表的21位地址转换为1~4字节不等,具有与ASCII相容的优点。

UCS可以看作是字符到码点的直接映射,UTF可以看作是在码点上的进一步变换。

若从21位编码地址的意义上看,UCS-4/UTF-32/UTF-8是无损的。

若从编码有效字符的意义上看,UCS-4/UTF-32/UTF-16/UTF-8是无损的。

具体编码规则请自行Wiki。

BOM:即Byte Order Mark,在文件开头用于表示字节序(一般常见于UTF-16)。Unicode中,U+FEFF表示ZERO WIDTH NO- BREAK SPACE字符,而U+FFFE不是有效字符。在UTF-16编码的文件开头加上U+FEFF这个字符,那么进行流式传输时,如果收到->FE->FF,则表示Big Endian,如果收到->FF->FE,则表示Little Endian。UTF-8不需要BOM,因为其编码规则决定了可以正确地按字节进行解码。但也有些程序会在开头加上EF BB BF这样的字节以表示自己的UTF-8身份(讨厌!)。

Note. 为什么在文本文件开头加上非内容的东西?虽然编辑器里看起来没什么不一样,自己解析的时候还是很烦(需要判断,判断为真还要bypass掉)。关于Little Endian和Big Endian的争论几十年而不休。人类总是期望制定统一的标准而后让标准因为各自利益而崩塌。我个人无比憧憬着endianness的统一和B OM的移除(这也算是我prefer UTF-8的一个理由)。

Note. 我极度不理解现在的编码方式。人们试图用一个很大的容器去覆盖所有的东西,发现它效率不够高,于是打了一个个补丁,最后造出一个丑陋的怪玩意儿(如果不是 双射那就更加没有美感)。过了几十年发现自己当年十分愚弱无知,那个当年看似很大的容器现在忽然很小,不够用了,然后一个新方法又被提出来,然而也只不过是上一个容器 的扩增版。什么时候能从一开始就设计一个scalable的标准出来?比如说,按字节编码,保留1个8-bit数表示“此字节表示扩展,东西在后面字节里”,不就可以 串行做下去了么?常用的扔前面,不常用的扔后面不就完了么?在此基础上爱想什么压缩想什么压缩去。我希望我这辈子能亲眼看到UCS-4不够用了,反正我见过一次千年虫 了,也parse过烦死人的UTF-16文档了。