计算机用二进制数储存的信息,但二进制不符合人的直观认知,我们通过计算机看到的文字(英文字母、汉字、符号等)都是二进制数转换之后的结果。这里就涉及到编码和解码。
'A'
,现在要把它以二进制码 0100 0001
存储于计算机中。这种将字符转换成 二进制数字的过程就叫字符编码。0100 0001
转换成字符 'A'
的过程就叫做字符解码。对于有些许混淆的同学,可以这么理解这两个概念。
字节 (Byte)
是物理存储单元的单位,首先我们先从 位 (b, bit) 说,位是数据存储的最小单位,每个二进制数0或者1就是1个位。8个位构成一个字节 (B, Byte) 。位和字节是实实在在表示数据在计算机中所占用存储空间大小的单位。
字符 (Character)
实际字符是一个注入了文化属性的计算机术语(个人理解),例如 'A'
就是一个表示英文字母A的字符, '树'
是一个表示中文汉字的字符。字符是一个表示事文字、符号等的基本单位,它是不可拆解的。
对于汉字, '木'
、 '又'
、 '寸'
三个字符拼起来是 '木又寸'
,它不是 '树'
吗,怎么不可拆分? '木'
、 '又'
、 '寸'
和 '树'
这是四分别独立的字符,学写字的时候我们都知道,虽然有偏旁组合,但他们每个字都是写在一个“田字格”里的,这里也同理, '木又寸'
占了 3 个“田字格”,它就是 3 个字符嘛。
字符和字节
一个字符占用几个字节?答案是:难说!,但有据可查。比如有如下图这么大的方框空间,打上田字格写汉字,能写下1个;但是打上四线三格写拼音(英文字母),却可以写下2个;当然你只想写一个,也没得问题。
所以说,这个 t
到底是占 1 个格子还是占 0.5 个格子要看书写方式是怎么规定的。同理,一个字符具体占用几个字节就需要查阅它的字符编码方式。
首先说说字符集和字符编码。
字符编码 (Character Encoding)
一个 t
到底占几个格子?请给出一个说法。
字符编码即对上述问题进行约定,并做出一系列相关规定。它是一套法则。
字符集 (Charset)
上面说到了字符,t
用在计算机里哪个数字表示?那么把包括所有文字、标点符号、图形符号、数字等的字符归拢到一起形成的字典(这里的字典就是《新华字典》的字典的意思,无他),就是字符集。
接下来我们讨是论的这些哪些是字符集,哪些是字符编码呢?
最开始计算机只在美国人用,他们的语言只需要52个(算上大小写)英文字母,加上一些数字,标点,符号和控制字符之类的,拢共100多个就够用了。
所谓控制字符就是作为特殊的用途的,一但终端、打印机遇上约定好的这些字节被传过来时,就要做一些约定的动作。例如遇上0×10, 终端就换行,遇上0×07, 终端就向人们嘟嘟叫。控制字符有32个。接下来就是空格、标点符号、数字、大小写字母分别用连续的字节状态表示,一直到127 。
后来又发现有了一些非英文的新的字母、符号等被需要,于是从 128~255
派给了拓展打印字符。这就是ASCII (American Standard Code for Information Interchange,美国信息互换标准代码) 字符集,ASCII字符集分为3部分:
这样以后,英语语言国家用起来可就没啥问题了,但是中国和世界其他语言国家还是没法使用自己的语言。
面向中文的字符编码主要有GB2312、GBK、GB18030和Big5几种,其发展历程大概如下。
下面逐一说明。
中国有6000多个常用汉字,显然一个字节的宽度是不够表示这么多汉字的,需要两个字节。因此规定:
0xA1
用到 0xF7
,后面一个字节(低字节)从 0xA1
到 0xFE
。这样组合出约7000多个简体汉字。此外还把数学符号、罗马希腊的字母、日文的假名们注入,连在 ASCII 里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的”全角”字符;而原来在127号以下的那些就叫”半角”字符了。 这种方案叫做 GB2312 (GB是国家标准的意思),它是对 ASCII 的中文扩展。
为解决繁体字、生僻字的问题。不再要求低字节一定是127号之后的内码,只要第一个字节是大于127就固定表示这是一个汉字的开始,不管后面跟的是不是扩展字符集里的内容。结果扩展之后的编码方案被称为 GBK (国标-扩),GBK 包括了 GB2312 的所有内容,同时又增加了近20000个新的汉字(包括繁体字)和符号。
为解决少数民族文字问题,再扩展几千个新的少数民族文字字,GBK 扩成了 GB18030 。
这一系列汉字编码的标准通称做双字节字符集 (Double Byte Charecter Set,DBCS)。在DBCS系列标准里,最大的特点是两字节长的汉字字符和一字节长的英文字符并存于同一套编码方案里,因此他们写的程序为了支持中文处理,必须要注意字串里的每一个字节的值,如果这个值是大于127的,那么就认为一个双字节字符集里的字符出现了。
英文名 Big5 ,中文名叫 五大码,也叫 *大五码 。
GB2312 不支持繁体汉字,在港澳台地区为统一繁体字符集编码,台湾五大厂商宏碁、神通、佳佳、零壹以及大众一同制定了一种繁体中文编码方案,就是大五码。其中繁体汉字13053个,808个标点符号、希腊字母及特殊符号。大五码的编码码表直接针对存储而设计,每个字符统一使用两个字节存储表示。第1字节范围 81H~FEH
,避开了同ASCII码的冲突,第2字节范围是 40H~7EH
和 A1H~FEH
。因为Big5的字符编码范围同GB2312字符的存储码范围存在冲突,所以在同一正文不能对两种字符集的字符同时支持。
上面说的是中文字符集与编码,那其他国家也都有自己的一套,比如韩国人自己搞的编码叫韩EUC-KR编码。各个国家的字符编码标准一套又一套,互相之间兼容性又不好。不同的语言字符编码值相同却代表不同的符号 (例如韩文编码EUC-KR中“한국어”的编码值正好是汉字编码GBK中的“茄惫绢”)。同一份文档拷贝至不同语言的机器可能成了乱码。咋办?
一种简单粗暴的方法:废除所有的地区性编码方案,重新搞一个包括了地球上所有文化、所有字母和符号的编码。出现了两种声音:
1991年前后,两个项目的参与者都认识到,世界不需要两个不兼容的字符集。于是,它们开始合并双方的工作成果。从Unicode 2.0开始,Unicode 采用了与 ISO 10646-1相同的字库和字码。两个项目仍都独立存在,并独立地公布各自的标准。
不过由于 Unicode 这一名字比较好记,因而它使用更为广泛。
Unicode 的编码范围为 U+0000 ~ U+10FFFF
,整个编码空间划分为17个 Plane (通常翻译为"平面")。每个平面包含 2 16 2^{16} 216 个代码点 (code point),拢共有 1114112 个。
2 16 × 17 = 1114112 2^{16} × 17 = 1114112 216×17=1114112
所谓代码点,就是文字符号在Unicode 中对应的那个值, 通常写成 U+ABCD
的格式。
平面的概念源于UTF-16编码,其中0号空间叫做基本多文种平面 (Basic Multilingual Plane, BMP),其他平面叫做补充平面(supplementary planes)。
Plane | 范围 | 名称 |
---|---|---|
Plane 0 | U+0000 ~ U+FFFF | 基本多文种平面(Basic Multilingual Plane, BMP) |
Plane 1 | U+10000 ~ U+1FFFF | 多文种补充平面(Supplementary Multilingual Plane, SMP) |
Plane 2 | U+20000 ~ U+2FFFF | 表意文字补充平面(Supplementary Ideographic Plane, SIP) |
Plane 3 | U+30000 ~ U+3FFFF | 表意文字第三平面(Tertiary Ideographic Plane, TIP) |
Plane 4~13 | U+40000 ~ U+4FFFF | 未使用(unassigned) |
Plane 14 | U+E0000 ~ U+EFFFF | 特别用途补充平面(Supplementary Special-purpose Plane, SSP) |
Plane 15~16 | U+F0000 ~ U+10FFFF | 保留作为私人使用区(Private Use Area, PUA) |
在Unicode与ISO 10646合并之前,ISO 10646 标准为 UCS 定义了一种用四个字节来表示代码点的方式,编码空间为 0x00000000~0x7FFFFFFF
,这就是 UCS-4 (Universal Character Set coded in 4 octets)。
此外,还定义了一种两字节表示的编码形式,即UCS-2。
UCS-4 有20多亿个编码空间,但实际使用范围并不超过0x10FFFF,并且为了兼容Unicode标准,ISO也承诺将不会为超出0x10FFFF的UCS-4编码赋值。由此 UTF-32 (32-bit Unicode Transformation Format) 编码被提出来了,它的编码值与 UCS-4 相同,只不过其编码空间被限定在了 0~0x10FFFF
之间。因此可以说UTF-32是UCS-4的一个子集。
此外由于 UCS-2 的两字节并不够用,于是出现了 UTF-16 ,与UCS-2一样,它使用两个字节为全世界最常用的63K字符编码,不同的是,它使用4个字节对不常用的字符进行编码。UTF-16属于变长编码。
在没有辅助平面字符 (Surrogate Code Points)前,UTF-16与UCS-2所指的是同一的意思。但当引入辅助平面字符后,就称为 UTF-16 了。现在若有软件声称自己支持UCS-2编码,那其实是暗指它不能支持在UTF-16中超过2字节的字集。对于小于0x10000的UCS码,UTF-16编码就等于UCS码。这里 UTF-16 可看成是 UCS-2 的父集。
无论是 UTF-16/32 还是 UCS-2/4,一个字符都需要多个字节来编码,显然有些浪费。由此 UTF-8 产生了。在UTF-8编码中,ASCII码中的字符还是ASCII码的值,只需要一个字节表示,其余的字符需要2字节、3字节或4字节来表示。
0~0x7F
,所有编码的二进制值中第一位为 0(这个正好可以用来区分单字节编码和多字节编码)。字节数 | Unicode | UTF-8 |
---|---|---|
1 | 000000-00007F | 0xxxxxxx |
2 | 000080-0007FF | 110xxxxx 10xxxxxx |
3 | 000800-00FFFF | 1110xxxx 10xxxxxx 10xxxxxx |
4 | 010000-10FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
编码方式 | 最少字节数 | 最多字节数 | 是否依赖字节序 |
---|---|---|---|
UCS-4 | 4 | 4 | 是 |
UCS-2 | 2 | 2 | 是 |
UTF-32 | 4 | 4 | 是 |
UTF-16 | 2 | 4 | 是 |
UTF-8 | 1 | 4 | 否 |
ANSI 编码实际是微软面向全世界的 Windows 用户设置的一种依区域自动匹配编码的方案,实际还是上面我们介绍的编码中的一种。有需要请看我的另一篇。
本文参考了
[1]. GB2312、GBK、GB18030 这几种字符集的主要区别是什么?
https://www.zhihu.com/question/19677619
[2]. 细说:Unicode, UTF-8, UTF-16, UTF-32, UCS-2, UCS-4
https://www.cnblogs.com/malecrab/p/5300503.html
[3]. Unicode了解一下:码位分布
https://blog.csdn.net/oyji1992/article/details/80030366
[4]. ASCII、Unicode、GBK和UTF-8字符编码的区别联系
https://www.cnblogs.com/shytong/p/5848640.html
[5]. Standard Encodings
https://docs.python.org/3.6/library/codecs.html#standard-encodings
[6]. Unicode 和 UTF-8 有什么区别?
https://www.zhihu.com/question/23374078
[7]. 字符集和字符编码(Charset & Encoding)
https://www.runoob.com/w3cnote/charset-encoding.html
.
.
.
.
.
.
桃花仙人种桃树,又摘桃花换酒钱_