字符与编码,傻傻分不清楚

 

计算机中储存的信息都是用二进制数表示的。通俗的说,按照何种规则将字符存储在计算机中,称为”编码”;反之,将二进制数解析显示出来,称为”解码”。

一、基本概念

字符集(Charset):是一个系统支持的所有抽象字符的集合。字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。常见的字符集有ASCII字符集GB2312字符集Unicode字符集

字符编码(Character Encoding):是一套法则,使用该法则能够对自然语言的字符的一个集合(如字母表或音节表),与其他东西的一个集合(如号码或电脉冲)进行配对。即在符号集合与数字系统之间建立对应关系,它是信息处理的一项基本技术。

二、编码模型

2.1. ASCII字符集与编码

ASCII字符集:主要包括控制字符(回车键、退格、换行键等);可显示字符(英文大小写字符、阿拉伯数字和西文符号)。

ASCII编码:将ASCII字符集转换为计算机可以接受的数字系统的数的规则。使用7位(bits)表示一个字符,共128字符;但是7位编码的字符集只能支持128个字符,为了表示更多的欧洲常用字符对ASCII进行了扩展,ASCII扩展字符集使用8位(bits)表示一个字符,共256字符。

2.2. 再讲讲 Unicode 和 UTF-32、UTF-16、UTF-8

简单来说:Unicode是字符集,UTF-32、UTF-16、UTF-8是三种字符编码方案。

2.2.1 Unicode字符集

当计算机传到世界各个国家时,为了适合当地语言和字符,例如中国设计和实现GB2312/GBK/GB18030/BIG5的编码方案。每个地区这样各搞一套,在本地使用没有问题,一旦出现在网络中,由于不兼容,互相访问就出现了乱码现象。

为了解决这个问题,一个伟大的创想产生了 —— Unicode。Unicode字符集为表达任意语言的任意字符而设计。它使用4字节的数字来表达每个字母、符号,或者表意文字(ideograph)。每个数字代表唯一的至少在某种语言中使用的符号(并不是所有的数字都用上了,但是总数已经超过了65535,所以2个字节是不够用的)。即每个字符对应一个数字,每个数字对应一个字符,不存在二义性。例如,U+0041总是代表’A’,即使这种语言没有’A’这个字符。

2.2.2 UTF-32编码

编码方式:每个字符都使用4字节。

就空间而言,是非常没有效率的。这种方法的优点就是可以在常数时间内定位字符串里的第N个字符。

2.2.3 UTF-16编码

尽管有Unicode字符非常多,但是实际上大多数人不会用到超过前65535个以外的字符。因此,就有了另外一种Unicode编码方式,叫做UTF-16。UTF-16将0–65535范围内的字符编码成2个字节,如果真的需要表达那些很少使用的”星芒层(astral plane)”内超过这65535范围的Unicode字符,则需要使用一些诡异的技巧来实现。

编码方式

  1. 如果字符编码U小于0x10000,也就是十进制的0到65535之内,则直接使用1个两字节表示;

  2. 如果字符编码U大于0x10000,由于UNICODE编码范围最大为0x10FFFF,从0x10000到0x10FFFF之间共有0xFFFFF个编码,也就是需要20个bit就可以标示这些编码。用U’表示从0-0xFFFFF之间的值,将其前10 bit作为高位和16bit的数值0xD800进行逻辑or操作,将后10bit作为低位和0xDC00做逻辑or操作,这样组成的2个两字节就构成了U的编码。

UTF-16编码最明显的优点是它在空间效率上比UTF-32高两倍,因为每个字符只需要2个字节来存储(除去65535范围以外的),而不是UTF-32中的4个字节。并且,如果我们假设某个字符串不包含任何星芒层中的字符,那么我们依然可以在常数时间内找到其中的第N个字符,直到它不成立为止这总是一个不错的推断。

2.2.4 UTF-8编码

UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码,也是一种前缀码。它可以用来表示Unicode标准中的任何字符,且其编码中的第一个字节仍与ASCII兼容,这使得原来处理ASCII字符的软件无须或只须做少部份修改,即可继续使用。因此,它逐渐成为电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。

编码方式

使用1至4个字节作为每个字符编码:

  1. 128个US-ASCII字符只需1字节编码(Unicode范围由U+0000至U+007F)。

  2. 带有附加符号的拉丁文、希腊文、西里尔字母、亚美尼亚语、希伯来文、阿拉伯文、叙利亚文及它拿字母则需要2字节编码(Unicode范围由U+0080至U+07FF)。

  3. 其他基本多文种平面(BMP)中的字符(这包含了大部分常用字)使用3字节编码。

  4. 其他极少使用的Unicode辅助平面的字符使用4字节编码。

2.2.5 总结

对于UTF-32和UTF-16编码方式还有一些其他不明显的缺点。不同的计算机系统会以不同的顺序保存字节。以UTF-16为例,这意味着字符U+4E2D(称为编码单元)可能被保存为4E 2D或者2D 4E(即这个编码单元为2字节,而编码单元内部的字节顺序不确定),这取决于该系统使用的是大尾端还是小尾端。

UTF-8则不会有这种问题(因为utf8是变长编码,而且是单字节为编码单元,不存在谁在高位、谁在低位的问题,所以不存在顺序问题。顺便说一下解码,由于utf8的首字节记录了总字节数(比如3个),所以读取首字节后,再读取后续字节(2个),然后进行解码,得到完整的字节数,从而保证解码也是正确的)。