2、字符编码简史:ASCII码的诞生、EASCII的扩展、ANSI与本地化编码
字符编码这事儿,说白了就是给每个字符发一个身份证号。计算机只认0和1,但我们要在上面写英文、中文、日文,怎么办?那就得约定一套规则——哪个数字代表'A',哪个数字代表'我'。
这套规则,就是字符编码。今天咱们聊聊它的早期历史。我个人觉得,搞懂这段历史,你就能理解为什么后来会出现那么多乱码问题。
2.1 ASCII码的诞生:一个字节的起点
上世纪60年代,美国标准化协会(ANSI的前身)搞出了一套编码方案,叫ASCII(American Standard Code for Information Interchange)。
为什么是7位?因为当时电报和通信设备用的是7位数据位。7位能表示128个字符(2^7=128),对英文来说,够了。
| 范围 | 类别 | 示例 |
|---|---|---|
| 0-31 | 控制字符 | NUL(0)、LF(10)、CR(13) |
| 32 | 空格 | SP |
| 33-47 | 标点符号 | ! " # $ % & ' ( ) * + , - . / |
| 48-57 | 数字 | 0-9 |
| 58-64 | 标点符号 | : ; < = > ? @ |
| 65-90 | 大写字母 | A-Z |
| 91-96 | 标点符号 | [ \ ] ^ _ ` |
| 97-122 | 小写字母 | a-z |
| 123-127 | 标点符号 | { | } ~ DEL |
核心要点:ASCII只用了7位,最高位(第8位)始终为0。这意味着一个字节(8位)里,有128个位置是空的。
我刚开始学编程时,以为ASCII就是全部。后来遇到一个项目,需要处理法语文本,结果é字符直接变成了乱码。嗯,那时候我才意识到——ASCII只覆盖了英语。
2.2 EASCII的扩展:把第8位用起来
既然ASCII只用了7位,那第8位闲着也是闲着。于是,各种扩展ASCII(EASCII)出现了。它们把128-255这128个位置填上了各种符号。
但问题来了——谁来填?
不同的厂商、不同的地区,填的内容完全不一样。比如IBM的Code Page 437,把128-255填上了画线符号、数学符号和一些欧洲字母。而ISO 8859-1(Latin-1)则填上了西欧语言需要的字符。
| 编码名称 | 范围 | 特点 |
|---|---|---|
| ASCII | 0-127 | 7位,标准英文 |
| Code Page 437 | 0-255 | IBM PC原始字符集,含画线符号 |
| ISO 8859-1 | 0-255 | 西欧语言,Latin-1 |
| ISO 8859-5 | 0-255 | 西里尔字母(俄语等) |
| ISO 8859-6 | 0-255 | 阿拉伯语 |
注意:EASCII不是统一标准。同一个字节0xC0,在Code Page 437里是"└",在ISO 8859-1里是"À"。如果你用错编码,看到的全是乱码。
我曾经帮一个同事排查乱码问题。他收到的文件里,所有"é"都变成了"é"。我一看就知道——这是UTF-8编码的文本被当成Latin-1解析了。这种坑,踩过一次就忘不了。
2.3 ANSI与本地化编码:一个混乱的时代
到了80年代,个人电脑普及了。微软在Windows里搞了一套"ANSI"编码的概念。但注意,这个"ANSI"其实是个伪标准——它指的是当前系统区域设置对应的编码。
什么意思?
你在中文Windows上,ANSI编码就是GBK(或GB2312)。你在日文Windows上,ANSI编码就是Shift_JIS。你在西欧Windows上,ANSI编码就是Windows-1252。
这就导致了一个经典问题:你用中文Windows保存了一个文本文件,发给日本同事,他打开全是乱码。为什么?因为他的ANSI编码是Shift_JIS,不是GBK。
避坑指南:我曾经在项目中遇到一个老系统,所有配置文件都用ANSI编码保存。后来系统要迁移到Linux服务器,结果所有中文注释全变成"????"。解决方案:统一使用UTF-8编码,并在文件头加BOM(虽然我不推荐BOM,但这是另一个话题)。
本地化编码的典型代表:
- GB2312 / GBK:中国大陆,简体中文。GB2312收录6763个汉字,GBK扩展到了21886个。
- Big5:台湾、香港,繁体中文。收录13053个汉字。
- Shift_JIS:日本,日文。同时支持英文和日文。
- EUC-KR:韩国,韩文。支持韩文字母和汉字。
- Windows-1252:西欧,Latin-1的微软变体。
你想想看,每个地区都有自己的编码。一个软件要支持多语言,就得在代码里写一堆编码转换逻辑。那个年代的程序员,谁没写过几行MultiByteToWideChar和WideCharToMultiByte?
2.4 核心逻辑:一张图看懂早期编码演变
下面这张图,是我自己梳理的。它展示了从ASCII到本地化编码的演变路径。
从这张图可以看得很清楚:ASCII是起点,EASCII是过渡,然后分成了两条路——一条是国际标准(ISO 8859系列),另一条是厂商标准(IBM、微软)。最终,这些标准又演变成了各个地区的本地化编码。
这个时期,编码世界是分裂的。每个地区、每个厂商都有自己的"方言"。直到Unicode的出现,才真正统一了天下。那是下一章的内容了。
总结一下:
- ASCII:7位,128个字符,只够英文用。
- EASCII:8位,256个字符,但标准不统一。
- ANSI/本地化编码:每个地区一套,互不兼容。
这个时期的编码,说白了就是"各说各话"。你写一个文件,换个系统打开就乱码。我当年做跨国项目时,光编码转换就写了上百行代码。现在回想起来,真是血泪史。