MENU

计算机编码学习

November 9, 2017 • Code

前言:计算机系统中的编码有非常悠久的历史,也正因此,许多编码的概念并不是十分明确的,下面就计算机中的编码做一个简单介绍。

主要内容

什么是 计算机编码

在我们日常生活中,用各种各样的语言进行交流,而每一种语言实际上就是一套字符集合,中文的「你」,英文的「you」等,都是字符。对于计算机而言,它的语言就是 01序列,所对应的字符集就是 01

  1. 在计算机中有一个表,当你输入 y 保存的时候,它去这个表里查对应的 01序列,找到了对应的 01序列 后就将其保存磁盘上,这里假设 y 对应的是 000110

  2. 下一次你要打开这个文件,计算机就去表里找对应 000110 的字符,得到 y 后,就可以显示出来

  3. y 在计算机中变成 000110 的过程就叫做编码(编成01代码串),反过来从 000110y 的过程叫解码

因为 000110 表示方式对人来说不直观。所以一般用十进制或十六进制表示,这里的 000110 对应着十进制中的 6

字符集字符编码

前面说了,一般字符需要经过编码之后才能让计算机识别和使用,所以如何设计编码转化的 是关键所在。而这张表就是字符集,而如何将表中的 与已知的 对应进行的规则称之为字符编码

举个栗子:
假设有一个字符集,用三个字节表示一个字符,其中

  • 0000 0000 0001 代表了字符 o

  • 0000 0001 0100 代表了字符 k

计算机读取 3 个字节,发现是 0000 0000 0001,明白了:哦,原来这个字符是o,再读取3个字节,发现是1100 0001 1110,明白了:原来这个字符是k

这里有一个问题:类似 0000 0000 0001 完全不需要三个字符来表示,但是字符集中又有需要用三个字节才能进行编码表示的字符,也就是说存在浪费空间的情况,这个时候就需要字符编码出场

比如可以通过用 01 0001 来表示 0000 0000 0001,用前面的 01 表示前面的字节全为 0,并且在字符集中这个位置的 01 不用来表示字符

字符集

计算机字符集按照所用字节数的多少可分为三类:单字节字符集(SBCS)多字节字符集(MBCS)宽字符集(即 Unicode 字符集)

  1. 单字节字符集(SBCS):表中的 01序列 为一个字节(8 bit),即用一个字节一个字符,如:ACSII

  2. 多字节字符集(MBCS):表中的 01序列 为一个或多个字节,即用一个或多个字节表示一个字符,如 ANSI 中的各种字符集

  3. 宽字符集:表中的 01序列 为 2 个字节,即用两个字节表示一个字符。(刚开始是定义 2 个字节来表示一个字符,后来新增加一组辅助平面编码(2 个字节),用 4 个字节表示一个字符)

介绍几种常用的字符集:

ASCII
  • 大小为 1 个字节(8 bit,可表示 0 ~ 255 共 256 个数),格式为0XXXXXXX

  • 填入了英文字符及一些不可见字符,如换行等

  • 填入后发现只用了一半的编码,即 128 个字符,但为了便于传输和保存,干脆在前面增加一个 0,这样刚好湊够一个字节

EASCII
  • 大小为 1 个字节,格式为 1XXXXXXX

  • 对 ASCII 的扩展,用了 ASCII 没用完的后面码位,最常见的扩展为 ISO/IEC 8859-1

ANSI
  • 最开始 ANSI 指 Windows 设计的一套编码,对应 Code Page 编号为 1252,故被称为 Windows 1252。由于 ANSI 是大部分参照 ANSI草案(ANSI Draft),并且这个 ANSI草案 后来成为了一个正式标准 ISO 8859-1,所以最开始的 ANSI 字符集和 ISO 8859-1 基本一样。

  • 但是在现在 ANSI 编码并不是指代一套特定的编码,而是是本地编码,可能在简体中文的 Windows 系统上 ANSI 指 GB2312,在日文 Windows 系统上 ANSI 编码代表 JIS 编码等。

ANSI 是在 ASCII 的基础上进行扩展的,故向下兼容 ASCII

中文编码

主要有:

  • GB2313
  • GBK
  • GB18030

关系:ASCII → GB2313 → GBK → GB18030 (包含的内容递增,并向下兼容)

Windows 下 cp936 编码指 GBK,因 GBK 在 Windows 系统中的代码页编号为 936

中文编码较为复杂,可以参考 字符编码详解——彻底理解掌握编码知识,“乱码”不复存在 中文编码部分

Unicode

截取部分如下:

统一码的编码方式与ISO 10646的通用字符集概念相对应。目前实际应用的统一码版本对应于UCS-2,使用16位的编码空间。也就是每个字符占用2个字节。这样理论上一共最多可以表示216(即65536)个字符。基本满足各种语言的使用。实际上当前版本的统一码并未完全使用这16位编码,而是保留了大量空间以作为特殊使用或将来扩展。

上述16位统一码字符构成基本多文种平面。最新(但未实际广泛使用)的统一码版本定义了16个辅助平面,两者合起来至少需要占据21位的编码空间,比3字节略少。但事实上辅助平面字符仍然占用4字节编码空间,与UCS-4保持一致。未来版本会扩充到ISO 10646-1实现级别3,即涵盖UCS-4的所有字符。UCS-4是一个更大的尚未填充完全的31位字符集,加上恒为0的首位,共需占据32位,即4字节。理论上最多能表示231个字符,完全可以涵盖一切语言所用的符号。

基本多文种平面的字符的编码为U+hhhh,其中每个h代表一个十六进制数字,与UCS-2编码完全相同。而其对应的4字节UCS-4编码后两个字节一致,前两个字节则所有位均为0。

字符编码

针对字符编码,需要注意的一点是字符集本身也可以看作是一种编码方式。如 GBKASCII 等,既可以指一张表(字符集),也指字符编码。如上面的例子,每一次去读取三个字节(整个字符集最大编码长度字节)也是一种编码方式,不过存在浪费空间的问题。所以上面列举的字符集也可以看作是一种编码方式

不过针对 Unicode 这种比较大的编码方式,每个字符用 4 个字节显然极为浪费,故常用的还是其它的编码方式。

Unicode 常用编码方式:

UTF-8
  • 可变长度 Unicode 字符编码
  • 采用 1~4 个字节来表示 Unicode 码

UTF-8 编码规则:

(图片截取自 字符编码笔记:ASCII,Unicode 和 UTF-8

UTF-16
  • 也是可变长度的Unicode字符编码

  • 采用2个字节或4个字节来表示Unicode编码

  • 大小端问题:由于有2个字节,在存放字符的时候,有两种存放方式,即高8码位放入高字节,低8码位放入低字节高8码位放入低字节,低8码位放入低字节,第一种称为 Little endian(LE,小端)第二种称为 Big endian(BE,大端)

Windows 下 Unicode 编码指 UTF-16 LE,Java 中 String 默认编码为 UTF-16 BE

Unicode 规范定义,为了让计算机能够识别打开的文本是用大端方式存储的还是小端方式存储的,在文件的开头部分增加一个表示顺序的字符零宽度非换行空格(zero width no-break space),如果这个字符是 FEFF,表示大头;如果是FFFE,表示小头

  • 与ASCII不兼容

以字母 a 为例子:

UTF-32
  • 不可变长度的 Unicode 字符编码
  • 采用 4 个字节来表示 Unicode 编码
  • 大小端问题
UCS-2
  • 也称标准 Unicode 编码,定长,每一次取 2 个字节作为 Unicode 码
  • 大小端问题。
UCS-4
  • 每一次取4个字节作为Unicode码
  • 大小端问题

关于BOM的问题

这是 Unicode 规范定义的,前面的大小端问题中零宽度非换行空格其实就是 UTF-16 的BOM。对于UTF-8而言,BOM为 EF BB BF。在Windows上带BOM的格式用的比较多,但是在Unix及Mac上用的不多。所以开发过程中能不用就尽量不用。用UTF-8 without BOM 最为稳妥(相对于用BOM来说)

内存编码 & 存储编码

UTF-8 等可变字符编码方案的优势在于节省空间及灵活,但也存在不足,即对齐困难

节省空间是相对于英文字符而言,中文字符在 UTF-8 中空间占用对比其它中文编码如 GBK 等并没有优势

所以在文件存储系统中优先选用 UTF-8,而在内存中,则优先选用对齐容易的编码方式,如等长字符编码,因为内存中对文件的操作极为频繁,如果格式不规整,会增加操作复杂度及时间。

内存编码与文件存储编码的关系如下(以 UTF-8 为栗):

两种编码对比如下:

参考

Last Modified: July 11, 2018
Archives QR Code
QR Code for this page
Tipping QR Code