一、编码的起源:从摩尔斯电码到ASCII,人类如何用0和1说话
编码这件事,说白了就是「约个暗号」。
我刚开始接触计算机时,总觉得0和1很神秘。后来做了十几年编解码,才明白——编码的本质,就是人类和机器之间的一种约定。你想想看,机器只认高低电平,但我们要在上面跑文字、图片、视频,怎么办?只能靠一套规则,把人类能懂的东西翻译成机器能懂的东西。
这一章,我们就从最早的编码讲起。看看人类是怎么一步步学会「用0和1说话」的。
1.1 摩尔斯电码:最早的「数字」通信
1837年,摩尔斯发明了电报。那时候没有电话,没有无线电,信息靠什么传?靠电线里的电流通断。
摩尔斯想了个办法:用短信号(点)和长信号(划)的组合来表示字母和数字。这就是摩尔斯电码。
核心思想:用两种基本符号(点、划)的组合,表示所有信息。这是人类历史上第一次用「离散符号」来编码连续信息。
举个例子,SOS这个求救信号:
S: ...(三个点)
O: ---(三个划)
S: ...(三个点)
→ 合起来就是 ... --- ...
我在项目中遇到过类似的情况。有一次调试一个嵌入式设备,串口日志全是乱码。我盯着波形看了半天,突然意识到——这不就是摩尔斯电码的思路吗?高低电平的时序组合,本质上和点划组合没有区别。从那以后,我对编码的理解就深了一层。
摩尔斯电码有几个关键特点:
- 可变长度编码:常用字母(如E)用短码,不常用字母(如Z)用长码
- 分隔符:点和划之间用短停顿,字母之间用长停顿,单词之间用更长停顿
- 冗余设计:有些码字故意设计得容易区分,减少误码
一个小技巧:摩尔斯电码的「常用字母用短码」这个思路,后来被霍夫曼编码发扬光大了。你如果学过数据压缩,会发现这其实就是熵编码的雏形。
1.2 从电报到计算机:为什么需要统一编码?
摩尔斯电码虽然好用,但它有个问题——不统一。不同国家、不同公司都有自己的变种。你发一份电报,对方可能用不同的码表来解读,结果就是乱码。
到了20世纪中期,计算机出现了。计算机用的是二进制,只有0和1。但怎么把字母、数字、符号映射到0和1上?
最早的做法是各搞各的。IBM的机器用一套码,DEC的机器用另一套。这就好比大家说不同的方言,没法交流。
我记得有一次帮客户做数据迁移,从一台老式IBM主机往新服务器上搬数据。结果发现字符编码不兼容,所有带特殊符号的字段全变成了乱码。折腾了两天,最后只能写脚本一个一个字符地映射。那时候我就想——要是早统一编码标准,哪来这么多破事?
1.3 ASCII:第一个真正意义上的字符编码标准
1963年,美国国家标准学会(ANSI)发布了ASCII(American Standard Code for Information Interchange)。这是计算机历史上最重要的编码标准之一。
ASCII用7位二进制数表示一个字符。7位能表示多少种组合?2^7 = 128种。这128个字符包括:
- 控制字符(0-31):换行、回车、退格等
- 可打印字符(32-126):字母、数字、标点符号
- 删除字符(127):DEL
我们来看一下ASCII的编码表(部分):
| 二进制 | 十进制 | 十六进制 | 字符 | 说明 |
|---|---|---|---|---|
| 01000001 | 65 | 41 | A | 大写字母A |
| 01000010 | 66 | 42 | B | 大写字母B |
| 01100001 | 97 | 61 | a | 小写字母a |
| 00110000 | 48 | 30 | 0 | 数字0 |
| 00100001 | 33 | 21 | ! | 感叹号 |
你可能会问:为什么A是65,而不是1?
嗯,这里有个设计上的考量。ASCII的设计者把字母、数字、符号分成了不同的区间,方便程序处理。比如:
- 数字0-9对应48-57,这样你只要判断一个字符的编码是否在48-57之间,就知道它是不是数字
- 大写字母A-Z对应65-90,小写字母a-z对应97-122
- 大小写字母之间正好差32,所以大写转小写只需要加32(或设置第6位为1)
注意:ASCII只定义了128个字符。但计算机通常用8位(一个字节)来存储字符。多出来的128个位置(128-255)怎么办?不同的厂商、不同的国家就各自定义了扩展ASCII。这又导致了新的不兼容问题——后来才有了Unicode。
1.4 从摩尔斯到ASCII:编码思想的演进
我们对比一下摩尔斯电码和ASCII,看看编码思想是怎么演进的:
| 维度 | 摩尔斯电码 | ASCII |
|---|---|---|
| 基本符号 | 点、划、停顿 | 0、1 |
| 编码长度 | 可变长度 | 固定长度(7位) |
| 分隔符 | 需要(停顿) | 不需要(定长) |
| 字符集大小 | 约50个(字母+数字) | 128个 |
| 应用场景 | 人工收发 | 计算机处理 |
你会发现,从摩尔斯到ASCII,编码思想发生了两个重要变化:
- 从可变长度到固定长度:固定长度编码不需要分隔符,计算机处理起来更简单、更快
- 从人工优化到机器优化:摩尔斯电码考虑的是人发报的效率和容错,ASCII考虑的是计算机处理的便利性
我建议你记住这个转变。因为后来所有的编码设计,本质上都是在「人」和「机器」之间找平衡。
1.5 编码的核心逻辑:一张图看懂
下面这张图展示了从信息到编码的核心流程。我画这张图的时候,特意把「约定」放在了中间——因为编码的本质就是约定。
1.6 避坑指南:编码问题常见的坑
做了这么多年编解码,我踩过的坑不少。分享几个最常见的:
我曾经在做一个跨平台项目时,Windows上写的文本文件拿到Linux上打开,所有换行都乱了。后来才发现——Windows用CRLF(\r\n)换行,Linux用LF(\n)换行。这就是编码约定不一致导致的典型问题。
- 坑1:文件编码声明与实际编码不一致——HTML页面声明UTF-8,但实际保存成了GBK,浏览器解析时就会乱码
- 坑2:数据库连接字符集没设置——程序里用UTF-8,数据库用Latin1,存进去再读出来就变成问号
- 坑3:BOM头问题——Windows记事本保存UTF-8文件时会加BOM头,但有些解析器不认这个BOM,导致第一行出现乱码
我的建议:所有新项目,统一用UTF-8。数据库、文件、网络传输,全部UTF-8。虽然UTF-8不是最省空间的编码,但它兼容ASCII,而且能表示所有Unicode字符。省心。
1.7 小结
这一章我们从摩尔斯电码讲到了ASCII。核心就三句话:
- 编码是约定——发送方和接收方必须用同一套规则
- 从可变到固定——固定长度编码让计算机处理更高效
- 从分散到统一——ASCII是第一个真正意义上的字符编码标准