字符编码也称字集码,是把字符集中的字符编码为指定集合中某一对象,以便文本在计算机中存储和通过通信网络的传递。常见的例子包括将拉丁字母表编码成摩斯电码和ASCII。
字符编码(英语:Character encoding)也称字集码,是把字符集中的字符编码为指定集合中某一对象(例如:比特模式、自然数序列、8 位组或者电脉冲),以便文本在计算机中存储和通过通信网络的传递。常见的例子包括将拉丁字母表编码成摩斯电码和 ASCII。其中,ASCII 将字母、数字和其它符号编号,并用 7 比特的二进制来表示这个整数。通常会额外使用一个扩充的比特,以便于以 1 个字节的方式存储。
在计算机技术发展的早期,如 ASCII(1963 年)和 EBCDIC(1964 年)这样的字符集逐渐成为标准。但这些字符集的局限很快就变得明显,于是人们开发了许多方法来扩展它们。对于支持包括东亚 CJK 字符家族在内的写作系统的要求能支持更大量的字符,并且需要一种系统而不是临时的方法实现这些字符的编码。
ASCII
美国(国家)信息交换标准(代)码,一种使用 7 个或 8 个二进制位进行编码的方案,最多可以给 256 个字符(包括字母、数字、标点符号、控制字符及其他符号)分配(或指定)数值。
ASCII 码于 1961 年提出,用于在不同计算机硬件和软件系统中实现数据传输标准化,在大多数的小型机和全部的个人计算机都使用此码。ASCII 码划分为两个集合:128 个字符的标准 ASCII 码和附加的 128 个字符的扩充和 ASCII 码。比较 EBCDIC。其中 95 个字符可以显示。另外 33 个不可以显示。 标准 ASCII 码为 7 位,扩充为 8 位。
目前使用最广泛的西文字符集及其编码是 ASCII 字符集和 ASCII 码( ASCII 是 American Standard Code for Information Interchange 的缩写),它同时也被国际标准化组织( International Organization for Standardization, ISO )批准为国际标准。
基本的 ASCII 字符集共有 128 个字符,其中有 96 个可打印字符,包括常用的字母、数字、标点符号等,另外还有 32 个控制字符。标准 ASCII 码使用 7 个二进位对字符进行编码,对应的 ISO 标准为 ISO646 标准。下表展示了基本 ASCII 字符集及其编码:
字母和数字的 ASCII 码的记忆是非常简单的。我们只要记住了一个字母或数字的 ASCII 码(例如记住 A 为 65 , 0 的 ASCII 码为 48 ),知道相应的大小写字母之间差 32 ,就可以推算出其余字母、数字的 ASCII 码。
虽然标准 ASCII 码是 7 位编码,但由于计算机基本处理单位为字节( 1byte = 8bit ),所以一般仍以一个字节来存放一个 ASCII 字符。每一个字节中多余出来的一位(最高位)在计算机内部通常保持为 0 (在数据传输时可用作奇偶校验位)。
由于标准 ASCII 字符集字符数目有限,在实际应用中往往无法满足要求。为此,国际标准化组织又制定了 ISO2022 标准,它规定了在保持与 ISO646 兼容的前提下将 ASCII 字符集扩充为 8 位代码的统一方法。 ISO 陆续制定了一批适用于不同地区的扩充 ASCII 字符集,每种扩充 ASCII 字符集分别可以扩充 128 个字符,这些扩充字符的编码均为高位为 1 的 8 位代码(即十进制数 128~255 ),称为扩展 ASCII 码。
通过了解字符的存储编码,可以解决很多由编码不匹配引起的问题,比如网页乱码、邮件乱码,本文简单扼要地阐明了 ASCII 编码、EBCDIC 编码、GB2312 编码、UTF-8 编码、以及 Base64 编码。
编码
在显示器上看见的文字、图片等信息在电脑里面其实并不是我们看见的样子,即使你知道所有信息都存储在硬盘里,把它拆开也看不见里面有任何东西,只有些盘片。假设,你用显微镜把盘片放大,会看见盘片表面凹凸不平,凸起的地方被磁化,凹的地方是没有被磁化;凸起的地方代表数字 1,凹的地方代表数字 0。硬盘只能用 0 和 1 来表示所有文字、图片等信息。那么字母”A”在硬盘上是如何存储的呢?可能小张计算机存储字母”A”是 1100001,而小王存储字母”A”是 11000010,这样双方交换信息时就会误解。比如小张把 1100001 发送给小王,小王并不认为 1100001 是字母”A”,可能认为这是字母”X”,于是小王在用记事本访问存储在硬盘上的 1100001 时,在屏幕上显示的就是字母”X”。也就是说,小张和小王使用了不同的编码表。小张用的编码表是 ASCII,ASCII 编码表把 26 个字母都一一的对应到 2 进制 1 和 0 上;小王用的编码表可能是 EBCDIC,只不过 EBCDIC 编码与 ASCII 编码中的字母和 01 的对应关系不同。一般地说,开放的操作系统(LINUX 、WINDOWS 等)采用 ASCII 编码,而大型主机系统(MVS 、OS/390 等)采用 EBCDIC 编码。在发送数据给对方前,需要事先告知对方自己所使用的编码,或者通过转码,使不同编码方案的两个系统可沟通自如。
ASCII 码使用 7 位 2 进制数表示一个字符,7 位 2 进制数可以表示出 2 的 7 次方个字符,共 128 个字符。EBCDIC 码使用 8 位,可以表示出 2 的 8 次方个字符,256 个字符。
无论是 ASCII 码还是 EBCDIC 码,都无法对拥有几万个的汉字进行编码。因为上面已经提过,7 位 2 进制数最多对应上 128 个字符,8 位最多对应上 256 个字符。
0~31 及 127(共 33 个)是控制字符或通信专用字符(其余为可显示字符),如控制符:LF(换行)、CR(回车)、FF(换页)、DEL(删除)、BS(退格)、BEL(振铃)等;通信专用字符:SOH(文头)、EOT(文尾)、ACK(确认)等;ASCII 值为 8、9、10 和 13 分别转换为退格、制表、换行和回车字符。它们并没有特定的图形显示,但会依不同的应用程序而对文本显示有不同的影响。
32~126(共 95 个)是字符(32sp 是空格),其中 48~57 为 0 到 9 十个阿拉伯数字,65~90 为 26 个大写英文字母,97~122 为 26 个小写字母,其余为一些标点符号、运算符号等。
MBCS
为了扩充 ASCII 编码,以用于显示本国的语言,不同的国家和地区制定了不同的标准,由此产生了 GB2312, BIG5, JIS 等各自的编码标准。这些使用 2 个字节来代表一个字符的各种汉字延伸编码方式,称为 ANSI 编码,又称为”MBCS(Muilti-Bytes Character Set,多字节字符集)”。在简体中文系统下,ANSI 编码代表 GB2312 编码,在日文操作系统下,ANSI 编码代表 JIS 编码,所以在中文 windows 下要转码成 gb2312,gbk 只需要把文本保存为 ANSI 编码即可。 不同 ANSI 编码之间互不兼容,当信息在国际间交流时,无法将属于两种语言的文字,存储在同一段 ANSI 编码的文本中。一个很大的缺点是,同一个编码值,在不同的编码体系里代表着不同的字。这样就容易造成混乱。导致了 unicode 码的诞生。
其中每个语言下的 ANSI 编码,都有一套一对一的编码转换器,Unicode 变成所有编码转换的中间介质。所有的编码都有一个转换器可以转换到 Unicode,而 Unicode 也可以转换到其他所有的编码。
GB2312
GB2312 也是 ANSI 编码里的一种,对 ANSI 编码最初始的 ASCII 编码进行扩充,为了满足国内在计算机中使用汉字的需要,中国国家标准总局发布了一系列的汉字字符集国家标准编码,统称为 GB 码,或国标码。其中最有影响的是于 1980 年发布的《信息交换用汉字编码字符集 基本集》,标准号为 GB 2312-1980,因其使用非常普遍,也常被通称为国标码。GB2312 编码通行于我国内地;新加坡等地也采用此编码。几乎所有的中文系统和国际化的软件都支持 GB 2312。
GB 2312 是一个简体中文字符集,由 6763 个常用汉字和 682 个全角的非汉字字符组成。其中汉字根据使用的频率分为两级。一级汉字 3755 个,二级汉字 3008 个。由于字符数量比较大,GB2312 采用了二维矩阵编码法对所有字符进行编码。首先构造一个 94 行 94 列的方阵,对每一行称为一个“区”,每一列称为一个“位”,然后将所有字符依照下表的规律填写到方阵中。这样所有的字符在方阵中都有一个唯一的位置,这个位置可以用区号、位号合成表示,称为字符的区位码。如第一个汉字“啊”出现在第 16 区的第 1 位上,其区位码为 1601。因为区位码同字符的位置是完全对应的,因此区位码同字符之间也是一一对应的。这样所有的字符都可通过其区位码转换为数字编码信息。GB2312 字符的排列分布情况见表 1-4。
表 1-4 GB2312 字符编码分布表
分区范围
符号类型
第 01 区
中文标点、数学符号以及一些特殊字符
第 02 区
各种各样的数学序号
第 03 区
全角西文字符
第 04 区
日文平假名
第 05 区
日文片假名
第 06 区
希腊字母表
第 07 区
俄文字母表
第 08 区
中文拼音字母表
第 09 区
制表符号
第 10-15 区
无字符
第 16-55 区
一级汉字(以拼音字母排序)
第 56-87 区
二级汉字(以部首笔画排序)
第 88-94 区
无字符
GB2312 字符在计算机中存储是以其区位码为基础的,其中汉字的区码和位码分别占一个存储单元,每个汉字占两个存储单元。由于区码和位码的取值范围都是在 1-94 之间,这样的范围同西文的存储表示冲突。例如汉字‘珀’在 GB2312 中的区位码为 7174,其两字节表示形式为 71,74;而两个西文字符‘GJ’的存储码也是 71,74。这种冲突将导致在解释编码时到底表示的是一个汉字还是两个西文字符将无法判断。
为避免同西文的存储发生冲突,GB2312 字符在进行存储时,通过将原来的每个字节第 8bit 设置为 1 同西文加以区别,如果第 8bit 为 0,则表示西文字符,否则表示 GB2312 中的字符。实际存储时,采用了将区位码的每个字节分别加上 A0H(160)的方法转换为存储码,计算机存储规则是此编码的补码,而且是位码在前,区码在后。例如汉字‘啊’的区位码为 1601,其存储码为 B0A1H,其转换过程为:
区位码
区码转换
位码转换
存储码
1001H
10H+A0H=B0H
01H+A0H=A1H
B0A1H
GB2312 编码用两个字节(8 位 2 进制)表示一个汉字,所以理论上最多可以表示 256×256=65536 个汉字。但这种编码方式也仅仅在中国行得通,如果您的网页使用的 GB2312 编码,那么很多外国人在浏览你的网页时就可能无法正常显示,因为其浏览器不支持 GB2312 编码。当然,中国人在浏览外国网页(比如日文)时,也会出现乱码或无法打开的情况,因为我们的浏览器没有安装日文的编码表。
GBK
GBK 即汉字内码扩展规范,K 为扩展的汉语拼音中“扩”字的声母。英文全称 Chinese Internal Code Specification。GBK 编码标准兼容 GB2312,共收录汉字 21003 个、符号 883 个,并提供 1894 个造字码位,简、繁体字融于一库。GB2312 码是中华人民共和国国家汉字信息交换用编码,全称《信息交换用汉字编码字符集——基本集》,1980 年由国家标准总局发布。基本集共收入汉字 6763 个和非汉字图形字符 682 个,通行于中国大陆。新加坡等地也使用此编码。GBK 是对 GB2312-80 的扩展,也就是 CP936 字码表 (Code Page 936)的扩展(之前 CP936 和 GB 2312-80 一模一样)。
基本简介
GB 2312 的出现,基本满足了汉字的计算机处理需要,但对于人名、古汉语等方面出现的罕用字,GB 2312 不能处理,这导致了后来 GBK 及 GB 18030 汉字字符集的出现。
GBK 采用双字节表示,总体编码范围为 8140-FEFE,首字节在 81-FE 之间,尾字节在 40-FE 之间,剔除 xx7F 一条线。总计 23940 个码位,共收入 21886 个汉字和图形符号,其中汉字(包括部首和构件)21003 个,图形符号 883 个。P-Windows3.2 和苹果 OS 以 GB2312 为基本汉字编码, Windows 95/98 则以 GBK 为基本汉字编码。
有些汉字用五笔和拼音都打不出来,如:溙(五笔 IDWI),须调出 GBK 字符集才能打出这个字。极品五笔中可右击输入法图标,设置,属性中选 GBK 字符集。极点五笔中可点击工具条中相关图标进行转换。
Big5
在台湾、香港与澳门地区,使用的是繁体中文字符集。而 1980 年发布的 GB2312 面向简体中文字符集,并不支持繁体汉字。在这些使用繁体中文字符集的地区,一度出现过很多不同厂商提出的字符集编码,这些编码彼此互不兼容,造成了信息交流的困难。为统一繁体字符集编码,1984 年,台湾五大厂商宏碁、神通、佳佳、零壹以及大众一同制定了一种繁体中文编码方案,因其来源被称为五大码,英文写作 Big5,后来按英文翻译回汉字后,普遍被称为大五码。
大五码是一种繁体中文汉字字符集,其中繁体汉字 13053 个,808 个标点符号、希腊字母及特殊符号。大五码的编码码表直接针对存储而设计,每个字符统一使用两个字节存储表示。第 1 字节范围 81H-FEH,避开了同 ASCII 码的冲突,第 2 字节范围是 40H-7EH 和 A1H-FEH。因为 Big5 的字符编码范围同 GB2312 字符的存储码范围存在冲突,所以在同一正文不能对两种字符集的字符同时支持。
Big5 编码的分布如表 1-5 所示,Big5 字符主要部分集中在三个段内:标点符号、希腊字母及特殊符号;常用汉字;非常用汉字。其余部分保留给其他厂商支持。
表 1-5 Big5 字符编码分布表
编码范围
符号类别
8140H-A0FEH
保留(用作造字区)
A140H-A3BFH
标点符号、希腊字母及特殊符号
A3C0H-A3FEH
保留(未开放用于造字区)
A440H-C67EH
常用汉字(先按笔划,再按部首排序)
C6A1H-C8FEH
保留(用作造字区)
C940H-F9D5H
非常用汉字(先按笔划,再按部首排序)
F9D6H-FEFEH
保留(用作造字区)
Big5 编码推出后,得到了繁体中文软件厂商的广泛支持,在使用繁体汉字的地区迅速普及使用。目前,Big5 编码在台湾、香港、澳门及其他海外华人中普遍使用,成为了繁体中文编码的事实标准。在互联网中检索繁体中文网站,所打开的网页中,大多都是通过 Big5 编码产生的文档。
Unicode
如上 ANSI 编码条例中所述,世界上存在着多种编码方式,在 ANSi 编码下,同一个编码值,在不同的编码体系里代表着不同的字。在简体中文系统下,ANSI 编码代表 GB2312 编码,在日文操作系统下,ANSI 编码代表 JIS 编码,可能最终显示的是中文,也可能显示的是日文。在 ANSI 编码体系下,要想打开一个文本文件,不但要知道它的编码方式,还要安装有对应编码表,否则就可能无法读取或出现乱码。为什么电子邮件和网页都经常会出现乱码,就是因为信息的提供者可能是日文的 ANSI 编码体系和信息的读取者可能是中文的编码体系,他们对同一个二进制编码值进行显示,采用了不同的编码,导致乱码。这个问题促使了 unicode 码的诞生。
如果有一种编码,将世界上所有的符号都纳入其中,无论是英文、日文、还是中文等,大家都使用这个编码表,就不会出现编码不匹配现象。每个符号对应一个唯一的编码,乱码问题就不存在了。这就是 Unicode 编码。
Unicode 当然是一个很大的集合,现在的规模可以容纳 100 多万个符号。每个符号的编码都不一样,比如,U+0639 表示阿拉伯字母 Ain,U+0041 表示英语的大写字母 A,“汉”这个字的 Unicode 编码是 U+6C49。
Unicode 固然统一了编码方式,但是它的效率不高,比如 UCS-4(Unicode 的标准之一)规定用 4 个字节存储一个符号,那么每个英文字母前都必然有三个字节是 0,这对存储和传输来说都很耗资源。
UTF-8
为了提高 Unicode 的编码效率,于是就出现了 UTF-8 编码。UTF-8 可以根据不同的符号自动选择编码的长短。比如英文字母可以只用 1 个字节就够了。
UTF-8 的编码是这样得出来的,以”汉”这个字为例:
“汉”字的 Unicode 编码是 U+00006C49,然后把 U+00006C49 通过 UTF-8 编码器进行编码,最后输出的 UTF-8 编码是 E6B189。
Base64
有的电子邮件系统(比如国外信箱)不支持非英文字母(比如汉字)传输,这是历史原因造成的(认为只有美国会使用电子邮件?)。因为一个英文字母使用 ASCII 编码来存储,占存储器的 1 个字节(8 位),实际上只用了 7 位 2 进制来存储,第一位并没有使用,设置为 0,所以,这样的系统认为凡是第一位是 1 的字节都是错误的。而有的编码方案(比如 GB2312)不但使用多个字节编码一个字符,并且第一位经常是 1,于是邮件系统就把 1 换成 0,这样收到邮件的人就会发现邮件乱码。
为了能让邮件系统正常的收发信件,就需要把由其他编码存储的符号转换成 ASCII 码来传输。比如,在一端发送 GB2312 编码->根据 Base64 规则->转换成 ASCII 码,接收端收到 ASCII 码->根据 Base64 规则->还原到 GB2312 编码。。