unicode笔记

标签(空格分隔): unicode


  • 解释
      Unicode是一种字符编码方法,是由国际组织设计,目的是容纳全世界所有语言文字的编码方案。Unicode的学名是"Universal Multiple-Octet Coded Character Set",简称为UCS。UCS可以看作是"Unicode Character Set"的缩写。
      任何文字在Unicode中都对应一个值,这个值称为代码点(code point)。
      Unicode 的实现方式称为 Unicode转换格式(Unicode Transformation Format,简称为 UTF)。unicode主要有三种编码实现:一类 32 位形式(UTF-32)、一类 16 位形式(UTF-16)和一类 8 位形式(UTF-8)。

  • ASCII 编码

ASCII(American Standard Code for Information Interchange,美国信息互换标准代码),是基于拉丁字母的一套电脑编码系统,1967年美国首次公布编码标准,它主要用于显示现代英语和其他西欧语言。它是现今最通用的单字节编码系统,并等同于国际标准ISO/IEC 646。

ASCII 码一共规定了128个字符的编码,比如空格SPACE是32(二进制00100000),大写的字母A是65(二进制01000001)。这128个符号,只占用了一个字节的后面7位,最前面的一位统一规定为0。
  ASCII 字符集由95个可打印字符(0x20-0x7E)和33个控制字符(0x00-0x1F,0x7F)组成。可打印字符用于显示在输出设备上,例如荧屏或者打印纸上,控制字符用于向计算机发出一些特殊指令,例如0x07会让计算机发出哔的一声,0x00通常用于指示字符串的结束,0x0D和0x0A用于指示打印机的打印针头退到行首(回车)并移到下一行(换行).

  • latin1 编码
      Latin1是ISO-8859-1的别名,有些环境下写作Latin-1。ISO-8859-1编码是单字节编码,向下兼容ASCII,其编码范围是 0x00-0xFF,0x00-0x7F之间完全和ASCII一致,0x80-0x9F之间是控制字符,0xA0-0xFF之间是文字符号。

  • UCS-2、UCS-4、BMP
      UCS有两种格式:UCS-2和UCS-4,都是固定字节编码。顾名思义,UCS-2就是用2个字节编码,UCS-4就是用4个字节(实际上只用了31位,最高位必须为0)编码。基本多语言平面内,从U+D800到U+DFFF之间的码位区段是永久保留不映射到Unicode字符
      UCS-2有216=65536个码位(为了兼容Unicode,0xD800-0xDFFF之间的码位未使用),UCS-4有231=2147483648个码位。
      UCS-4根据最高位为0的最高字节分成2^7=128个group。每个group再根据次高字节分为256个plane。每个plane根据第3个字节分为256行 (rows),每行包含256个cells。当然同一行的cells只是最后一个字节不同,其余都相同。
      Unicode编码点分为17个平面(plane),每个平面包含2^16(即65536)个码位(code point),而第一个平面称为“基本多语言平面”(Basic Multilingual Plane,简称BMP),其余平面称为“辅助平面”(Supplementary Planes)。17个平面的码位可表示为从U+xx0000到U+xxFFFF,其中xx表示十六进制值从0x00到0x10,共计17个平面。其中BMP(0x00000xFFFF)中0xD8000xDFFF之间的码位作为保留,未使用。
      UCS-2用2个字节编码,只能编码BMP中的字符。此时UTF-16与UCS-2的编码一样(都直接使用Unicode的码位作为编码值)。
      将UCS-4的BMP去掉前面的两个零字节就得到了UCS-2。在UCS-2的两个字节前加上两个零字节,就得到了UCS-4的BMP。而目前的UCS-4规范中还没有任何字符被分配在BMP之外。

  • UTF-16

UTF-16是字符编码表(Character Encoding Form,也称为 "storage format")的一种实现方式。即把Unicode字符集的抽象码位映射为16位长的整数(即码元, 长度为2 Byte)的序列,用于数据存储或传递。Unicode字符的码位,需要1个或者2个16位长的码元来表示,因此这是一个变长表示。

UTF-16可以表示所有的unicode编码点的字符,即0x000000 ~ 0x10FFFF的所有字符,对于BMP的字符,采用一个码元表示,对于从0x010000~0x10FFFF的字符,则采用2个码元表示。具体的表示如下表:

Unicode范围 UTF-16编码方式
U+0000 ~ U+FFFF 2 Byte存储,编码后等于Unicode值
U+10000 ~ U+10FFFF 4 Byte存储,现将Unicode值减去(0x10000),得到20bit长的值。再将Unicode分为高10位和低10位。UTF-16编码的高位是2 Byte,高10位Unicode范围为0-0x3FF,将Unicode值加上0XD800,得到高位代理(或称为前导代理,存储高位);低位也是2 Byte,低十位Unicode范围一样为0~0x3FF,将Unicode值加上0xDC00,得到低位代理(或称为后尾代理,存储低位)

根据上面的转换方式,我们就能够将Unicode码根据UTF-16的编码方式进行转换。下面我们仍然通过两个例子来看下:
  U+0020,这个值的范围在第一部分,即经过UTF-16编码后,结果仍然为U+0020,在内存中的顺序为00 20。
  U+12345, 这个值的范围在第二部分,因此需要先减去0x10000,得到0x02345,二进制表示为 0000 0010 0011 0100 0101,拆分成高10位00 0000 1000(0x0008)和低10位11 0100 0101(0x0345)。根据上面规则加上特定值后,高位代理值为 0x0008 + 0xD800 = 0xD808,低位代理值为0x0345 + 0xDC00 = 0xDF45,最终内存中的顺序为D8 08 DF 45。

  • UTF-32

UTF-32是字符编码表(Character Encoding Form,也称为 "storage format")的一种实现方式,固定用4个字节表示Unicode的编码字符。
  UTF-32直接用4个字节存储unicode编码字符,因此并不需要对编码进行算法转换,并且可以表示所有UCS-4码位。

  • UTF-8

UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码,又称万国码。由Ken Thompson于1992年创建。现在已经标准化为RFC 3629。UTF-8用1到6个字节编码Unicode字符。用在网页上可以统一页面显示中文简体繁体及其它语言(如英文,日文,韩文)。

UTF-8对于所有的unicode编码点的字符,即0x000000 ~ 0x10FFFF的所有字符,需要14个字节编码,也就是常说的UTF-8的字节范围为14;UTF-8可表示所有的UCS-4码位,这时需要1~6个字节。
  
UTF-8的编码规则很简单,只有二条:
  1. 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。
  2. 对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。
  下表总结了编码规则,字母x表示可用编码的位。

Unicode符号范围(十六进制) UTF-8编码方式(二进制)
0000 0000-0000 007F 0xxxxxxx
0000 0080-0000 07FF 110xxxxx 10xxxxxx
0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

根据上表,解读 UTF-8 编码非常简单。如果一个字节的第一位是0,则这个字节单独就是一个字符;如果第一位是1,则连续有多少个1,就表示当前字符占用多少个字节。
  下面,以汉字严为例,演示如何实现 UTF-8 编码。
  严的 Unicode 是4E25(0100 1110 0010 0101),根据上表,可以发现4E25处在第三行的范围内(0000 0800 - 0000 FFFF),因此严的 UTF-8 编码需要三个字节,即格式是1110xxxx 10xxxxxx 10xxxxxx。然后,从严的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。将严的二进制数 0100 1110 0010 0101 划分成 0100 111000 100101 这样就得到了,严的 UTF-8 编码是 11100100 10111000 10100101,转换成十六进制就是E4B8A5

128 个 ASCII 字符(Unicode 范围由 U+0000 至 U+007F)只需一个字节,带有变音符号的拉丁文、希腊文、西里尔字母、亚美尼亚语、希伯来文、阿拉伯文、叙利亚文及马尔代夫语(Unicode 范围由 U+0080 至 U+07FF)需要二个字节,其他基本多文种平面(BMP)中的字符(CJK(中日韩统一表意文字)属于此类)使用三个字节,其他 Unicode 辅助平面的字符使用四字节编码。
  
  占2个字节的:带有附加符号的拉丁文、希腊文、西里尔字母、亚美尼亚语、希伯来文、阿拉伯文、叙利亚文及它拿字母则需要二个字节编码
  占3个字节的:基本等同于GBK,含21000多个汉字
  占4个字节的:中日韩超大字符集里面的汉字,有5万多个
  一个utf8数字占1个字节
  一个utf8英文字母占1个字节
  少数汉字是每个占用3个字节,多数占用4个字节。根据维基百科中日韩统一表意文字的统计,至2020年,汉字unicode编码中总共收录92857个汉字,其中位于BMP的共有27594个汉字。
  
  占用3个字节的范围

U+2E80 - U+2EF3 : 0xE2 0xBA 0x80 - 0xE2 0xBB 0xB3 共 115 个
U+2F00 - U+2FD5 : 0xE2 0xBC 0x80 - 0xE2 0xBF 0x95 共 213 个
U+3005 - U+3029 : 0xE3 0x80 0x85 - 0xE3 0x80 0xA9 共 36 个
U+3038 - U+4DB5 : 0xE3 0x80 0xB8 - 0xE4 0xB6 0xB5 共 7549 个
U+4E00 - U+FA6A : 0xE4 0xB8 0x80 - 0xEF 0xA9 0xAA 共 44138 个
U+FA70 - U+FAD9 : 0xEF 0xA9 0xB0 - 0xEF 0xAB 0x99 共 105 个

合计: 52156 个

占用4个字节的范围

U+20000 - U+2FA1D : 0xF0 0xA0 0x80 0x80 - 0xF0 0xAF 0xA8 0x9D 共 64029 个

合计: 64029 个

  • Little endian 和 Big endian

big endian和little endian是CPU处理多字节数的不同方式。例如“汉”字的Unicode编码是6C49。那么写到文件里时,究竟是将6C写在前面,还是将49写在前面?如果将6C写在前面,就是big endian。还是将49写在前面,就是little endian。
  “endian”这个词出自《格列佛游记》。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开,由此曾发生过六次叛乱,其中一个皇帝送了命,另一个丢了王位。
  我们一般将endian翻译成“字节序”,将big endian和little endian称作“大尾”和“小尾”。

  • UTF的字节序和BOM

UTF-8以字节为编码单元,没有字节序的问题。UTF-16以两个字节为编码单元,在解释一个UTF-16文本前,首先要弄清楚每个编码单元的字节序。例如收到一个“奎”的Unicode编码是594E,“乙”的Unicode编码是4E59。如果我们收到UTF-16字节流“594E”,那么这是“奎”还是“乙”?
  Unicode规范中推荐的标记字节顺序的方法是BOM。BOM不是“Bill Of Material”的BOM表,而是Byte Order Mark。BOM是一个有点小聪明的想法:
  在UCS编码中有一个叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中。UCS规范建议我们在传输字节流前,先传输字符"ZERO WIDTH NO-BREAK SPACE"。
  这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little-Endian的。因此字符"ZERO WIDTH NO-BREAK SPACE"又被称作BOM。
  UTF-8不需要BOM来表明字节顺序,但可以用BOM来表明编码方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8编码是EF BB BF。所以如果接收者收到以EF BB BF开头的字节流,就知道这是UTF-8编码了。
  Windows就是使用BOM来标记文本文件的编码方式的。
  对于UTF-16编码,big endian的写法是加FE FF,little endian 的写法是加FF FE;而对于UTF-32编码,big endian的写法是加 00 00 FE FF,little endian 的写法是加FF FE 00 00 。

参考资料

  1. Unicode中UTF-8与UTF-16编码详解
  2. 程序员趣味读物:谈谈Unicode编码
  3. 字符编码笔记:ASCII,Unicode 和 UTF-8
  4. UTF-8编码占几个字节?

你可能感兴趣的:(unicode笔记)