Unicode详解

转自 Unicode标准以及其常见的编码方案

作者:luizyao
出处:https://www.cnblogs.com/luizyao/
版权:本文版权归作者所有
转载:欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出

Unicode

百度百科上,对Unicode的介绍是这样的:

“ Unicode(统一码、万国码、单一码)是计算机科学领域里的一项业界标准,包括字符集、编码方案等。Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。”

Unicode标准为每一个字符提供一个唯一的数字,而不用区分平台、语言等因素。

The Unicode Standard provides a unique number for every character, no matter what platform, device, application or language.

Unicode源于一个很简单的想法:将全世界所有的字符包含在一个集合里,计算机只要支持这一个字符集,就能显示所有的字符,再也不会有乱码了。

它从0开始,为每个符号指定一个编号,这叫做"码位"(code point)(字符码)。比如,码位U+0639表示阿拉伯字母Ain,码位U+0041表示英语的大写字母A,码位U+4E25表示汉字

目前,Unicode从7.0版开始,几乎每年一个新版本(Unicode 12.1.0 2019年5月7号)。

基本概念

在开始学习之前,我们需要先了解本文所涉及到的一些基本概念。

抽象字符(Abstract character):用于组织、控制或者表示文本数据的信息单元。

  • 抽象字符没有具体的形式,不应与图像字符(glyph)混淆。
  • 抽象字符不一定对应于人们所认知的“字”,不应与字素(grapheme)混淆。
  • 不能被Unicode标准直接编码的抽象字符通常可以通过组合字符序列来表示。

抽象字符序列(Abstract character sequence):一个或多个抽象字符的有序序列。

Unicode编码空间(Unicode codespace):十六进制0x0~0x10FFFF之间的整数。

码位(Code point):Unicode编码空间中的任意值。

编码字符(Coded character):当抽象字符被映射或者分配到编码空间中特定的码位时,它就被称为编码字符。

码位

码位是Unicode标准中很重要的一个概念。目前它的取值范围是十六进制的0x0~0x10FFFF,换算成十进制是0~1114111,共计1114112个。

需要注意的是,一个单一的抽象字符可能对应一个以上的码位。例如,Ω既可以表示大写的希腊字母Omega,码位是U+03A9,也可以表示物理学中的欧姆符号,码位是U+2126

>>> '\u03a9'
'Ω'
>>> '\u2126'
'Ω'

单个抽象字符也可以由一系列码位的序列来表示。例如,é的码位是U+00E9,它也可以由小写字母e(码位为U+0065'(Combining Acute Accent)(码位为U+0301)组合而成。

>>> '\u00e9'
'é'
>>> '\u0065\u0301'
'é'

在Unicode标准中,码位的表示方法通常是使用它们的十六进制,并加上U+前缀。

码位的类型

码位的分类方法多种多样。我们通过下表来阐明Unicode标准使用的七种类型和一些术语。

基本类型 简要描述 是否分配给
抽象字符
码位范围
图形(Graphic) 字母、标记、数字、标点符号、符号和空格
格式(Format) 不可见但是影响相邻字符。包括行、段落分割符
控制(Control) Unicode标准以外的协议或标准定义的用法 U+0000~U+001F,U+007F,U+0080~U+009F,共计65个
私用(Private-use) Unicode标准以外的私有协议定义的用法
代理 (Surrogate) 永久预留给UTF-16编码方案 不允许分配 U+D800~U+DFFF,共计2048个
非字符(Noncharacter) 永久预留给内部使用 U+FDD0~U+FDEF,所有以FFFE或者FFFF结尾的码位,共计66个
保留(Reserved) 预留给将来使用

我们需要格外注意代理(Surrogate)类型,理解他有助于我们学习UTF-16。它总共包含2048个码位,码位空间为U+D800~U+DFFF。它由引发出两个新的概念:

高位代理(High-Surrogate):U+D800~U+DBFF范围内的码位,共计1024个。

低位代理(Low-Surrogate):U+DC00~U+DFFF范围内的码位,共计1024个。

关于它们更多的内容,稍后结合UTF-16再讨论。

编码方案

在介绍具体的编码方案之前,我们先明确一些新的基本概念。

Unicode标量值(Unicode scalar value):除去高位代理和低位代理之外,所有的Unicode码位,也就是U+0000~U+D7FF和U+E000~U+10FFFF范围内的码位。

编码单元(Code unit):最小的比特位组合,表示用于交换或处理的编码文本单元。Unicode标准中定义,UTF-8使用8比特的编码单元,UTF-16使用16比特的编码单元,UTF-32使用32比特的编码单元。

编码单元序列(Code unit sequence):一个或多个编码单元的有序序列。

UTF-32

UTF-32将每个Unicode标量值映射成一个无符号的32比特的编码单元,数值与Unicode标量值相同,这是一种定长的编码方案。

注意,UTF-32无法编码U+D800~U+DFFF之间的码位,因为它们不属于Unicode标量值。

>>> '\ud800'.encode('utf32')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'utf-32' codec can't encode character '\ud800' in position 0: surrogates not allowed

UTF-16

UTF-16将Unicode标量值中U+0000~U+D7FFU+E000~U+FFFF范围内的码位映射成一个无符号的16比特的编码单元,数值与Unicode标量值相同。将U+10000~U+10FFFF范围内的码位映射成一个代理对,所谓的代理对就是上文提到的高位代理和低位代理。UTF-16是一种定长和变长兼顾的编码方案。

UTF-16编码以16位无符号整数为单位。我们把Unicode编码记作U。编码规则如下(百度百科):

  • 如果U<0x10000,U的UTF-16编码就是U对应的16位无符号整数(为书写简便,下文将16位无符号整数记作WORD)。
  • 如果U≥0x10000,我们先计算U'=U-0x10000,然后将U'写成二进制形式:0000 yyyy yyyy yyxx xxxx xxxx(前四位0舍弃),U的UTF-16编码(二进制)就是:110110yyyyyyyyyy 110111xxxxxxxxxx
Unicode标量值 UTF-16
U<0x10000 xxxx xxxx xxxx xxxx
U≥0x10000 1101 10yy yyyy yyyy 1101 11xx xxxx xxxx
xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx
000u uuuu xxxx xxxx xxxx xxxx 1101 10ww wwxx xxxx 1101 11xx xxxx xxxx

其中, U'=U-0x10000, 再将U'拆分
其中, wwww = uuuuu - 1

以字符𐌂(Old Italic Letter Ke)为例,它的码位是U+10302,二进制表示是0000 0001 0000 0011 0000 0010,减去U+10000(二进制为0000 0001 0000 0000 0000 0000),得到0000 0000 0000 0011 0000 0010(前四位0舍弃)。从右到左填充进模版,得到1101 1000 0000 0000 1101 1111 0000 0010,对应的十六进制是D800 DF02

U+10302 = 0000 0001 0000 0011 0000 0010
U+10302 - U+10000 =   0000 0001 0000 0011 0000 0010
                    - 0000 0001 0000 0000 0000 0000
                  =   0000 0000 0000 0011 0000 0010
UTF-16 = 1101 1000 0000 0000    1101 1111 0000 0010                  
>>> '\U00010302'.encode('utf-16be') #'𐌂'.encode('utf-16be')
b'\xd8\x00\xdf\x02'

UTF-8

UTF-8将每个Unicode标量值映射成一到四个无符号的8比特的编码单元,这是一种变长的编码方案。

下表阐明了UTF-8的编码方式。

Unicode标量值 第一个字节 第二个字节 第三个字节 第四个字节
00000000 0xxxxxxx 0xxxxxxx
00000yyy yyxxxxxx 110yyyyy 10xxxxxx
zzzzyyyy yyxxxxxx 1110zzzz 10yyyyyy 10xxxxxx
000uuuuu zzzzyyyy yyxxxxxx 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx

仍然以字符𐌂(Old Italic Letter Ke)为例,它的码位是U+10302,二进制表示是00000001 00000011 00000010,套用表中的模式,得到 11110000 10010000 10001100 10000010,对应的十六进制是F090 8C82。

00000001 00000011 00000010
000uuuuu zzzzyyyy yyxxxxxx

11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
11110000 10010000 10001100 10000010
>>> '\U00010302'.encode('utf-8') #'𐌂'.encode('utf-8')
b'\xf0\x90\x8c\x82'

下表阐明了UTF-8的所有有效编码范围。

Unicode标量值范围 第一个字节 第二个字节 第三个字节 第四个字节
U+0000 ~ U+007F 00 ~ 7F
U+0080 ~ U+07FF C2 ~ DF 80 ~ BF
U+0800 ~ U+0FFF E0 A0 ~ BF 80 ~ BF
U+1000 ~ U+CFFF E1 ~ EC 80 ~ BF 80 ~ BF
U+D000 ~ U+D7FF ED 80 ~ 9F 80 ~ BF
U+E000 ~ U+FFFF EE ~ EF 80 ~ BF 80 ~ BF
U+10000 ~ U+3FFFF F0 90 ~ BF 80 ~ BF 80 ~ BF 80 ~ BF
U+40000 ~ U+FFFFF F1 ~ F3 80 ~ BF 80 ~ BF 80 ~ BF
U+100000 ~ U+10FFFF F4 80 ~ 8F 80 ~ BF 80 ~ BF 80 ~ BF

参考资料

  1. UnicodeStandard-12.0:https://www.unicode.org/versions/Unicode12.1.0/
posted @ 2020-04-10 16:17  一花一世界,一叶一乾坤  阅读(2479)  评论(0编辑  收藏  举报