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 (7位, 0-127) EASCII (8位, 0-255) Code Page 437 (IBM) ISO 8859-1 至 8859-16 Windows-1252 (微软) 本地化编码 (GBK/Big5/Shift_JIS等) 每个地区都有自己的编码标准,互不兼容——这就是乱码的根源

从这张图可以看得很清楚:ASCII是起点,EASCII是过渡,然后分成了两条路——一条是国际标准(ISO 8859系列),另一条是厂商标准(IBM、微软)。最终,这些标准又演变成了各个地区的本地化编码。

这个时期,编码世界是分裂的。每个地区、每个厂商都有自己的"方言"。直到Unicode的出现,才真正统一了天下。那是下一章的内容了。

总结一下:

  • ASCII:7位,128个字符,只够英文用。
  • EASCII:8位,256个字符,但标准不统一。
  • ANSI/本地化编码:每个地区一套,互不兼容。

这个时期的编码,说白了就是"各说各话"。你写一个文件,换个系统打开就乱码。我当年做跨国项目时,光编码转换就写了上百行代码。现在回想起来,真是血泪史。