历史的车轮 — 编码史
最早最早, 我们的计算机仅仅是用来做数字运算的, 所以没有编码这回事. 后来人们发现可以使用计算机做更多的事情, 所以首先就是要想办法编码字符, 也就是使用二进制来表示字符. 所以在1963和1964年由IBM为大型机操作系统开发制定了一个编码标准, 类似ASCII, 叫做扩展二进制编码的十进制交换码 — (EBCDIC). 但是这个编码标准设计的太糟糕了, 就连英文字母都不是连续的, 造成很多困扰和麻烦. 所以在后来出现了个人计算机的时候, 大家都使用了ASCII编码标准.
顺便说个笑话:
教授:"所以美国政府去IBM提出了一个加密标准,他们想出了..."
学生:“EBCDIC!”
ASCII
事实上, ASCII的标准制定工作比上面的EBCDIC的制定还要早一点, 它的第一版和EBCDIC同一年出版, 接着在1967年进行重大更新, 目前最新的修订发生在1986年.
ASCII的全称是美国信息交换标准码, 可以说是最基础、最重要、应用最广泛一个字符编码方案. 所以现在大部分的通行编码方案都兼容ASCII编码. 至于EBCDIC, 你看我连个二级标题都没给他...应该是凉了.
接下来我们来简单说说ASCII编码方案吧, 它使用八个比特位, 但实际上只有7位在用, 因为规定最高位始终置零(在某些场合用来做奇偶校验). 这样就应该可以表示128个字符, 对于English来说, 完全够了.
- 0-31 都是控制字符和不可打印字符
- 32-126 是可打印可显示的字符 - 数字, 字母, 符号.
- 127 控制字符DEL.
这里的转换很简单, 不存在什么编码算法, 也没有什么码元序列和字节序列的转换. ASCII字符集标准就是ISO/IEC-646标准.
EASCII
渐渐地, 计算机从美国流传到了欧洲各国, 由于各种欧洲国家的语言中存在英语中不存在的一些字符, 例如一些衍生的拉丁字符, 所以他们就想要使用ASCII标准没有使用的最高位. 可是这样终究还是有限的 表示的字符数量变成了256个.
多出来的那128个就是最高位置1的结果, 表示出来的符号包括表格符号、计算符号、希腊字母和特殊的拉丁符号.
不过这一个标准也很少使用了, 这是因为后来ISO制定和发布了著名的ISO-8859系列标准.
ISO-8859
这个和上面的两个就不一样了, ISO/IEC-8859是一套标准, 一共包含从ISO-8859-1到ISO-8859-16, 除去已经被废弃的ISO-8859-12, 总共有15个标准. 这些标准涵盖了欧洲各国使用的字符, 甚至包括一些外来语. 而且每一个具体的标准都只是用了扩展ASCII的0xA0-0xFF
, 即160-255这96个编码.
GB系列
渐渐地, 计算机发展到了亚洲地区. 于是自然, 需要想个办法来表示这些亚洲地区文字. 以汉字为例, 汉字的表示和英语不同, 鉴于其表示的特殊性和复杂性, 中国相关部门设计了GB系列编码, GB就是国标的汉语拼音的缩写, 国家标准的意思. GB的编码规则向下兼容ASCII, 如果一个字节是0-127, 那么就字节的含义还是ASCII制定的含义. 但是当出现ASCII单字节和GB多字节混合使用的时候, 就要先将GB编码的最高位设置成1, 以防止冲突.
对了, 凡是GB系列的编码, 都是符合ISO-8859标准的.
GB2312
这是最早的中文国家标准, 诞生于1980年. 目前GB2312仍然被广泛使用, 它一共包括了6763个汉字, 还收录了包括拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母在内的682个字符.GB2312-1980通过 这6763个汉字已经足够日常使用. GB2312的编码方法和EASCII类似, 都是使用ASCII不使用的最高位, 它规定所有的汉字必须大于127, 然后必须和原本ASCII一起结合使用, 正因为此, 他不能兼容EASCII的扩展部分.
由于当时的计算机仍然是终端和文本模式的时代, 而每个字符都是一个小点阵, 占8个像素宽, 而汉字并不适合这样展示, 所以又出现了全角和半角的区别. 全角的标点符号和半角的标点符号在中文输入法下是一样的, 而在英文输入法中, 半角标点的宽度就是全角的一半大小. 关于全角半角, 我们在后面还会提到.
GB13000 / GBK
1993年, Unicode1.1标准(ISO/IEC 10646.1:1993)第一部分发布(关于Unicode和ISO10646的相关, 我们在后面会说), 随后中国就发布了新的国标: GB13000-1993. 这一个标准和前面的那两个相一致. 后来在2010年, 发布了替代标准GB13000-2010, 和ISO/IEC10646:2003保持一致.
提一嘴, GB13000的资料在网络上很少. 几乎搜不到什么相关信息
由于汉字的数量实在是太庞大了, 而一些人名, 古汉语, 生僻字都没有被包括在GB2312标准中, 所以同一年(1993), GBK, (即国家标准扩展的汉语拼音缩写)被定义, 尽管这个时候这并不是官方的标准, 但微软已经在Windows 95中实现了GBK的代码页(cp936). 由于Windows的广泛使用, 使得GBK成为了当时的事实标准. 于是, 在1995年, 国家发布GBK1.0规范, 对于cp936做了轻微的扩展. 但是目前的状态是, cp936就等同于GBK, 尽管GBK比cp936多出95个字符. IANA也把cp936作为GBK的别名.
GBK不同于GB2312, 汉字依然从127开始, 但是不要求使用原来的ASCII的比特位, 这样才能表示更多的字符.
GB18030
这个是目前最新的国家标准, 制定于2000年, 以取代GBK.在2005年, 国家对GB18030进行了补充, 在GBK的基础上增加了CJK.
微软也对GB18030制定了代码页(CP54936), 不过, 在(Windows7)系统的设置中并不能找到这个代码页, 只不过在Command Line中可以进行切换.
GB系列的编码方式(以GB2312为例)
首先我们明确, GB系列的汉字编码都是双字节编码, 也就是1个汉字相当于是2个英文字符.
接下来, 我们正式开始.
我们要先来说几个概念, 再逐渐引入这些概念的过程中, 就来解释GB2312的编码.
- 区位码
- 国标码
- 内码
- 外码
- 字形码
就直接从上到下说吧, 对于GB2312字符集, 我们把它分成94个区, 至于为什么是94个区, 是因为GB2312是7位双字节编码, 也就是128*128
, 由于需要避开ASCII的控制字符和空格(至于为什么后面再解释), 所以就只剩下了94*94
了. 结合上面所说的概念 — 编号空间, 码点空间. 这个94*94
的空间就是GB2312的编号空间了. 这样就可以通过一个横坐标一个纵坐标来唯一定位一个点, 这个横坐标就是区, 纵坐标就是位, 加在一起就是区位码. 这样说有点抽象. 其实, 高位字节就是这里的横坐标, 而低位字节就是纵坐标. 举个例子, 汉字字符: "万" 它的区位码是45 82, 所以45就代表高字节, 而82就代表低位字节.
在GB2312中, 是这样分区的:
1)01~09区(682个): 特殊符号、数字、英文字符、制表符等,包括拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母等在内的682个全角字符.
2)16~55区(3755个): 常用汉字(也称一级汉字), 按拼音排序
3)56~87区(3008个): 非常用汉字(也称二级汉字), 按部首/笔画排序
剩余的都是空区, 留作扩展.
你可能这个时候做了实验, 但是发现"万"好像并不是45 82
, 而是cd f2
. 这个继续往下看就知道了.
接下来回到刚刚说的, GB2312避开了ASCII的控制字符以及空格(从0H-20H, 0-32), 所以就导致整个编码开始于21H, 也就是10进制的33.
注意: 这里我为了简便, 略了另外一个字节, 正确的表示应该是(21H,21H)这样的, 因为双字节编码, 下同.
因此, 我们的编码就必须向后移动20H的位置(至于为什么要避开, 后面再说, 先别急), 即范围是从(21H, 21H)到(7E, 7E). 这样就进行了区位码到国际码的转换. 国际码又称作交换码, 那么还是用之前的"万"来做例子, "万"的国际码就是77 114
, 也就是十六进制的4d 72
.
说道这里, 可能敏感的你已经发现了, 第一: 4d 72
和之前的cd f2
还是不对应, 第二: 77 114
和ASCII已存在的字符发生了冲突, 例如, 这就和M, r
发生了冲突. 所以这个国际码并不能直接拿来用. 那咋办? 我们之前就说过了, 把ASCII没使用的最高位置1就行了, 即加上128, 80H.
值得一提的是, 这里的加上80H, 是微软提出的解决方案. 本质上他是改变了GB2312的编码方式. GB2312真正的规范编码, 到这里就结束了 — 国际码就是GB2312的规范编码.
这个时候"万"的GB2312编码就变成了之前的cd f2
了, 我们把这个最后的编码叫做内码. 意思就是计算机内部使用的编码.
现在我们就解释了GB系列的编码方式, 接下来就来回答一下上面的疑问: 为什么要避开那20H个. 说来也简单, 其实上面也已经解释了, 原本我们可以直接保留所有的ASCII编码的, 也就是直接从128开始编码, 但是考虑到全角和半角的英文字符, 所以GB2312就把这些重新进行编码加入到双字节编码的队列中. 而不可打印的控制字符, 也就是那20H, 32个就进行了保留, 这就是避开的原因.
最后我们再把外码和字形码说一下: 最简单的理解方式, 我们再输入的时候使用的代码就是外码, 例如五笔输入法, 拼音输入法这些, 规定的代码就是外码. 而字形码可以简单的理解成是我们的字体, 也即是具体的显示形状.
Big5
1984年策划制定, 主要用于台湾地区, 用于繁体汉字的显示, 可以读作大五码. 名字来自于台湾五家公司的财团.
这个就不展开说了, 他定义的汉字数量真的好少…好像还需要各种奇怪的扩展才能满足需要.
ANSI
我们在这里扩展一下, 说一下这个玩意. 在我们使用Windows的notepad的时候, 默认的存储编码方式是
ANSI
. 这是个什么玩意? 严格的说, 这不是一个编码方式, ANSI是美国国家标准协会的缩写. 它规定了各国字符编码对应的代码页标准, 例如我们在之前的概念中说过, GB系列的编码方式在Win中就是CP943, 当然这是指简体中文系统, 而繁体中文的Windows中, ANSI就对应Big5的代码页, 这就是说, 即使你们都是ANSI编码, 但不一定你们对应的文件编码是一致的.所以, 你也可以不严谨的说: ANSI是系统的默认编码方式, 不过这个也是会依靠系统语言而改变的. 另外只有Windows中存在这样的说法.