6.2 字符集
这一节中我们将讲述字符集的相关知识。字符集,即计算机中处理的所有字符的集合。在厘清字符集的概念之后,我们会对处理字符集时的注意事项进行简单说明。
- 什么是字符集
字符集,顾名思义,是一组字符的集合。大写英文字母(A、B、C、……Z)、数字(0、1、2、……9)等集合都是字符集。在计算机上处理字符集的时候,由于计算机中的信息都是以二进制方式存储的,如果直接处理字符的话会很不方便,所以给每个字符都分配一个编号(符号)来进行标识。严格来说,分配了编号(符号)的字符集叫作符号化字符集,不过本书的说明里都将统一使用字符集这一称呼。
表 6-1 是我们总结了比较常见的字符集列表。
表 6-1 常见字符集
字符集名称 位长 对应语言 说明 ASCII 7 位 英语 最早的标准化字符集 ISO-8859-1 8 位 西欧语言 在 ASCII 的基础上加上了法语、德语带声调的字符 JIS X 0201 8 位 英文、片假名 ASCII 和片假名 JIS X 0208 16 位 日语 包括第二基准在内的汉字 微软标准字符集 16 位 日语 JIS X 0201 和 JIS X 0208,以及 NEC 和日本 IBM 的非兼容字符 JIS X 0213 16 位 日语 包括第四基准在内的汉字 Unicode 21 位 多语言 实际共用的字符集 GB2312 16 位 简体中文 中国国家标准的简体中文字符集 GBK 16 位 中文 GBK 向下兼容 GB2312,同时增加了对繁体字的支持 GB18030 32 位 中文 集大成的字符集,兼容 GB2312 同时支持 Unicode - ASCII 和 ISO-8859-1
ASCII(American Standard Code for Information Interchange 的缩写,有时候也叫作 US-ASCII)是 1963 年美国制定的字符集。它使用 7 比特长的整数来表示在英语圈使用频繁的数字、字母(大小写)、各种符号等。ASCII 之前的字符集都是各厂商自己制定的,ASCII 作为共通的字符集标准,具有划时代的意义,对后来的字符集发展具有深远的影响。
ISO-8859-1 把 ASCII 扩展到 8 比特长,除了英语之外,又增加了法语和德语等西欧语言里的带音调的字符和符号等。ISO-8859-1 也经常被称为 Latin-1,作为 ASCII 的替代品,至今仍在广泛使用。
- JIS1 规定的字符集
JIS X 0201 是在 ASCII 扩展到 8 比特的基础上,加上了片假名及常用的日语符号的字符集。JIS X 0201 和 ASCII 有一部分编码是共通的(JIS X0201 是超级),但是也有两个例外,那就是 JIS X0201 将 ASCII 中 0x5C 表示的反斜线“\”替换为日元符号“¥”2 ,将 ASCII 中 0x7E 表示的波浪线替换为上划线(Overline)。尤其是反斜线是很容易发生安全隐患的特殊字符,要给予特别重视。
ASCII、ISO-8859-1、JIS X 0201 的包含关系如图 6-2 所示。
图 6-2 1 字节字符集的包含关系
由于 JIS X 0201 不包括日语中不可缺少的平假名和汉字,所以 1978 年制定了 JIS X 0208 字符集标准。JIS X 0208 包括平假名、片假名、汉字(包括第 1 基准 2965 字及第 2 基准 3390 字)等,使得计算机的日语处理大步前进。即使是到现在,JIS X 0208 也仍然保持着很大的影响力。
JIS X 0208 虽然也包括罗马字(英文字母)和数字,但是与 ASCII 或 JIS X 0201 采用了不同的编码体系。所以 JIS X 0208 的罗马字或者片假名又叫作“全角罗马字”“全角片假名”,ASCII 或 JIS X 0201 的字符叫作“半角字符”,将两者完全作为不同的字符来使用(“全角”和“半角”不是正式的叫法而是通常的称呼)。
之后到了 2000 年,向下兼容 JIS X 0208 的 JIS X 0213 发布了。JIS X 0213 增加了第 3 基准的 1259 个汉字和第 4 基准的 2436 个汉字。比如尾骶骨的“骶”就是第 3 基准的汉字。
最初我们在程序中不是必须要考虑到 JIS X 0213 的存在,但是随着 Windows Vista 支持全部的 JIS X 0213 字符,不知不觉中 JIS X 0213 也渐渐普及开来。
- 微软标准字符集
微软公司(现在日本微软)在 1993 年发布 Windows 3.1 日语版的时候,把之前各个厂商独自扩展的字符集统一起来,制定了微软标准字符集。从那之后,即使使用不同厂商生产的电脑,但只要是运行 Windows 3.1 的话,就可以使用共通的字符集了。
微软标准字符集在 JIS X 0201 和 JIS X 0208 的基础上又统一了 NEC 以及日本 IBM 的扩展字符集。NEC 扩展字符集比较有名的是类似“①”这样带圈的数字,日本 IBM 扩展汉字里比较有名的包括内田百閒 3 的“閒”,以及髙村薫的“髙”4 等。
微软标准字符集里像带圆圈的数字等很多字符后来都被 JIS X 0213 或者 Unicode 引入,现在都成为标准的字符了。而且,微软标准字符集本身也作为 CP932 代码页(CodePage)被广泛使用。关于 CP932 我们将在后面进行说明。
- Unicode
前面我们对日本字符集的历史做了简要的说明,除日本外,各国也都有各自不同的字符集。如果每个国家都制定并使用本国的字符集的话,既不利于信息的传播,也不利于软件产品的国际化,所以制定世界统一的字符集的呼声越来越高。以此为契机,计算机企业组成的小组制定了 Unicode 字符集。Unicode 的第一版 1.0 版是在 1993 年公布的,之后一直在不断完善,到本书翻译时 Unicode 的最新版为 6.2 版(2012 年 9 月 27 日公布)。
最开始制定 Unicode 字符集的时候,计划只用 16 比特就能够包罗世界上所有的字符,不过之后很快就发现这根本不够用,所以现在 Unicode 已经扩展到了 21 比特了。最初制定的 16 比特的编码则称为基本多语言平面(Basic Multilingual Plane,BMP)。
Unicode 编码里将文字编码成为码位(Code Point),用 U+XXXX(XXXX 为 4 位到 6 位的十六进制数)表示。比如,日语里的“表”的码位为 U+8868。
Unicode6.0 包括了之前我们介绍过的 ASCII、ISO-8859-1、JIS X 0201、JIS X 0208、JIS X 0213、微软标准字符集。图 6-3 显示了它们之间的包含关系。
图 6-3 多字节字符集之间的包含关系
- GB2312
GB2312 又称 GB2312-80 字符集,全称为“信息交换用汉字编码字符集·基本集”,由原中国国家标准总局发布,1981 年 5 月 1 日开始实施。GB2312 在中国大陆和新加坡被广泛使用,中国大陆几乎所有的中文软件都支持该字符集。
GB2312 是一个 16 位字符集,它是对 ASCII 的中文扩展并兼容 ASCII。GB2312 字符集一共收录了 6763 个汉字,其中一级汉字 3755 个,二级汉字 3008 个。同时它还收录了包括拉丁字母、希腊字母、日文平假名片假名等在内的 682 个字符。但不支持人名、古汉语等方面的罕用字和繁体字,这也导致了后来 GBK 和 GB18030 字符集的出现。
- GBK
GBK 即汉字内码扩展规范,它是 GB2312 编码的超集,向下完全兼容 GB2312,并支持 GB2312-80 编码不支持的部分中文姓、中文繁体、日文假名,以及希腊字母、俄语字母等字母。
不过 GBK 并不是国家标准,它最早实现于 Windows 95 简体中文版,也就是 CP936 字码表。微软的 CP936 通常被视为等同 GBK。
- GB18030
GB18030 全称为“信息交换用汉字编码字符集 ? 基本集的扩充”,是于 2000 年发布的新的汉字编码国家标准,它也兼容 GB2312 标准。
GB18030 编码是变长编码,有单字节、双字节和四字节三种方式,该标准支持超过 160 万的码位空间。最新版 GB18030-2005 兼容 Unicode 中日韩统一汉字,共收录了 70244 个汉字,覆盖了繁体和简体中文、日文、朝鲜语和中国少数民族(如藏、蒙古、傣、彝、维吾尔等)的文字。
- 不同字符相同编码的问题
我们在介绍 JIS X 0201 的时候已经说过了,即使编码相同,但是在不同的字符集里,表示的字符是不一样的。比如在安全上很容易出问题的反斜线“\”和日元符号“¥”就是这种情况。
在 ISO-8859-1 和 Unicode 里面,0xA5 是分配给日元符号“¥”的,然而在日本的字符编码里面,一直都是用 0x5C 来表示日元符号“¥”的。它们之间的关系可以参考表 6-2 对这两个字符在各个字符集的总结。5 6
表 6-2 字符集之间字符分配区别
字符集 0x5C 0xA5 ASCII \ %5 JIS X 0201 ¥ ·6 ISO-8859-1 \ ¥ Unicode \ ¥ GB2312 \ 非法字符 GBK \ 非法字符 GB18030 \ 非法字符 - 字符集的处理引起的漏洞
上面列出的字符集间对同一字符分配不同编码的问题,有时候会成为系统产生安全漏洞的原因。将 Unicode 的日元符号“¥”(U+00A5)转换为 JIS 系列编码的时候,根据处理方法的不同,为了保留原字符需要将此字符编码转换为 0x5C(JIS X0201 的日元符号)。而 0x5C(表示反斜线的编码)在需要转义的时候由于处理顺序等不同而导致转义操作被遗漏的时候,就有可能导致系统产生漏洞了。
反斜线在 SQL 语句里等是需要转义的对象字符,但是如果在日元符号“¥”(U+00A5)的状态下被转义,而之后又被转换为反斜线“\”的话,那么转义操作就跟没有做过一样了。7
1 日本工业规格(Japanese Industrial Standards,JIS),由日本工业标准调查会(JISC)组织制定和审议。——译者注
2 同时这也是人民币符号。——译者注
3 夏目漱石门下的小说家、散文家。——译者注
4 日本小说家、作家。髙是高的异体字。——译者注
5 因为 US-ASCII 是 7 比特的字符集,所以最高位的 1 比特会被忽略,被当作 0x25 进行处理。
6 半角的中点。
7 具体可以参考独立行政法人信息处理推进机构(IPA)的资料《安全调用 SQL 的方法》中的“A.3 由 Unicode 导致的 SQL 注入”。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论