2.2 ASCII与扩展编码
ASCII是最早的字符编码标准,也是所有现代编码的基础。这一节我们详细讲解ASCII编码以及后续的各种扩展编码。
ASCII编码详解
ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是1963年由美国国家标准学会制定的编码标准,主要用于显示现代英语和其他西欧语言。
ASCII编码的特点
- 总共包含128个字符,用7个二进制位表示
- 其中0-31和127是控制字符(如换行、回车、删除等)
- 32-126是可打印字符,包括英文字母、数字、常用符号
ASCII码表结构
| 码位范围 | 字符类型 | 说明 |
|---|---|---|
| 0-31 | 控制字符 | 不可打印,用于控制设备 |
| 32 | 空格 | 可打印 |
| 48-57 | 数字0-9 | 可打印 |
| 65-90 | 大写字母A-Z | 可打印 |
| 97-122 | 小写字母a-z | 可打印 |
| 其他 | 标点符号、特殊符号 | 可打印 |
| 127 | 删除控制符 | 控制字符 |
示例:
- ‘A’ → 65 → 二进制 01000001
- ‘a’ → 97 → 二进制 01100001
- ‘0’ → 48 → 二进制 00110000
- 空格 → 32 → 二进制 00100000
可以发现一个规律:同一个字母的大小写码位差32,这是一个很有用的特性,很多编程技巧都利用了这个特性。
ASCII的局限
ASCII最大的问题是只能表示英文字符,无法处理其他国家的语言。随着计算机在全球普及,这个问题越来越突出。
扩展ASCII编码
为了支持更多的字符,人们在ASCII的基础上进行了扩展,利用8位字节的最高位(原来ASCII只用到了低7位),这样就能表示256个字符。
ISO-8859系列编码
国际标准化组织(ISO)制定了一系列扩展ASCII编码标准,统称为ISO-8859系列:
- ISO-8859-1 (Latin-1):支持西欧语言
- ISO-8859-2 (Latin-2):支持中欧语言
- ISO-8859-3 (Latin-3):支持南欧语言
- ISO-8859-4 (Latin-4):支持北欧语言
- … 等等,共有15个标准
这些编码的低128位和ASCII完全兼容,高128位用于表示各个地区的特殊字符。
问题
ISO-8859系列解决了欧洲语言的编码问题,但还是无法支持像中文、日文这样字符数量巨大的亚洲语言,因为8位最多只能表示256个字符,远远不够。
中文编码标准
中文有上万个常用字符,8位字节完全不够用,所以中文编码使用了多字节编码方案,一个中文字符用2个或更多字节表示。
GB2312编码
GB2312是我国1980年发布的第一个中文编码标准:
- 全称《信息交换用汉字编码字符集·基本集》
- 共收录6763个常用汉字和682个非汉字符号
- 每个汉字用2个字节表示
- 低128位仍然和ASCII兼容,是对ASCII的中文扩展
- 兼容ASCII的部分称为半角字符,中文部分称为全角字符
编码规则:
- 第一个字节(高字节)范围:0xA1-0xF7
- 第二个字节(低字节)范围:0xA1-0xFE
- 两个字节的最高位都是1,和ASCII区分开
GBK编码
GB2312收录的汉字只有6763个,很多生僻字无法表示,所以1995年发布了GBK编码(汉字内码扩展规范):
- 共收录21003个汉字,包含了所有GB2312的汉字,同时增加了繁体汉字和更多生僻字
- 仍然是双字节编码
- 完全向下兼容GB2312
- 是Windows系统中文版本的默认编码
GB18030编码
为了支持更多的少数民族文字和 Unicode 字符,我国在2000年发布了GB18030编码:
- 采用1、2、4字节混合编码
- 收录了70244个汉字,包含了所有Unicode中的中文字符
- 完全向下兼容GB2312和GBK
- 是我国的国家强制标准
Big5编码
Big5是台湾、香港等地区使用的繁体中文编码标准:
- 双字节编码
- 收录13053个繁体汉字
- 和GB系列编码不兼容,同样的字节序列在GBK和Big5中表示不同的汉字,这就是为什么繁体网站如果编码不指定会出现乱码的原因。
多字节编码的问题
这些各个国家自己制定的扩展编码虽然解决了本国语言的表示问题,但带来了很多新的问题:
1. 不兼容问题
同一个二进制序列在不同的编码标准中可能代表完全不同的字符。例如:
- 字节序列
0xB0 0xA1在GBK编码中表示汉字“啊“ - 在Big5编码中表示汉字“屴“
- 在ISO-8859-1编码中表示两个特殊符号
这就导致如果没有指定编码,文本就无法正确解码,跨语言交流非常容易出现乱码。
2. 字符集有限
每个编码只能表示特定语言的字符,无法同时包含多种语言。例如一篇同时包含中文、日文、韩文的文档,就无法用单一的GBK或Shift_JIS编码来表示。
3. 处理复杂
多字节编码是变长的,有些字符是1字节,有些是2字节,处理字符串的时候很容易出问题:
- 计算字符串长度时需要区分单字节和多字节字符
- 截取字符串时很容易把一个多字节字符从中间截断,导致乱码
- 遍历字符串的复杂度比单字节编码高很多
正是因为这些问题,人们迫切需要一个全球统一的编码标准,这就催生了Unicode。
实践小技巧
在Windows系统中,如果遇到中文乱码,首先可以考虑是不是编码问题:
- 中国大陆的文件默认编码通常是GBK
- 台湾香港的文件默认编码通常是Big5
- 程序输出乱码通常是因为控制台编码和程序输出编码不一致
思考问题
- 为什么中文编码需要用多字节?单字节最多能表示多少个字符?
- GB2312、GBK、GB18030之间的关系是什么?
- 你遇到过GBK和UTF-8之间转换导致的乱码问题吗?当时是怎么解决的?