文字为什么能变成二进制?从 ASCII 到 Unicode 和 UTF-8
用 A、中、😀 三个例子说明字符、Unicode 码点、UTF-8 字节与二进制之间的关系,并解释为什么一个字符不一定等于一个字节。
文字不是直接“变成 0 和 1”
我们在聊天软件里输入一句话时,程序处理的是字符;真正写入文件、内存或网络的数据,则需要按照某种编码规则表示成字节。字节再由 bit 组成,因此最后可以写成一串 0 和 1。
这里最容易混淆的是:字符、Unicode 码点、编码后的字节和二进制位,不是同一个概念。
数字电路通常用两个可区分的逻辑状态来表示一个 bit,并把这两个状态记作 0 和 1。在本文讨论的现代 Web 和 UTF-8 语境中,1 个 byte(字节)就是 8 个 bit。但这并不意味着“一个字符一定占 8 个 bit”——字符要占多少字节,取决于使用的字符编码。
先分清四层:字符、码点、字节、bit
可以把文本保存过程理解成下面这条链路:
- 字符:人看到的文字或符号,例如
A、中、😀。 - Unicode 码点:Unicode 给字符分配的编号,例如
A是 U+0041。 - 编码后的字节:UTF-8 等编码方案把码点转换成一个或多个字节。
- bit:每个字节都可以继续写成 8 位二进制。
因此,“文字转二进制”并不是把字形直接翻译成 0 和 1,而是先确定字符的编号和编码方式,再得到具体字节。
ASCII:为什么 A 可以写成 01000001
ASCII 是早期英文文本中最常见的字符编码标准之一。标准 ASCII 使用 7 bit,可表示 128 个编号(0 到 127),包括英文字母、数字、标点和控制字符。
例如:
| 字符 | ASCII 十进制 | 十六进制字节 | 二进制 |
|---|---|---|---|
| A | 65 | 41 | 01000001 |
| B | 66 | 42 | 01000010 |
| a | 97 | 61 | 01100001 |
| 0 | 48 | 30 | 00110000 |
A 的 ASCII 编号是 65,也就是十六进制 0x41。如果把这个值放在一个 8 bit 的字节里,就是:
01000001
这也是为什么在 UTF-8 中,A 仍然只占 1 个字节:UTF-8 对 ASCII 的 0–127 范围保持兼容。
Unicode 和 UTF-8 分别解决什么问题
ASCII 的范围太小,无法表示汉字、绝大多数其他文字以及 emoji。Unicode 解决的是“每个字符应该对应哪个编号”的问题,这个编号叫码点(code point)。
例如:
A→ U+0041中→ U+4E2D😀→ U+1F600
但 Unicode 码点本身并不等于文件里的字节。还需要 UTF-8、UTF-16 等编码方案,把码点转换成实际字节序列。
UTF-8 是目前 Web 和跨平台文本交换中最常见的 Unicode 编码之一。它使用可变长度表示:一个 Unicode 码点会占 1 到 4 个字节。
A、中、😀 在 UTF-8 中到底是什么
下面三个例子都可以直接用程序验证:
| 字符 | Unicode 码点 | UTF-8 字节(十六进制) | UTF-8 字节(二进制) | 字节数 |
|---|---|---|---|---|
A |
U+0041 | 41 |
01000001 |
1 |
中 |
U+4E2D | E4 B8 AD |
11100100 10111000 10101101 |
3 |
😀 |
U+1F600 | F0 9F 98 80 |
11110000 10011111 10011000 10000000 |
4 |
所以:
A在 UTF-8 中是 1 个字节,也就是 8 bit。中在 UTF-8 中是 3 个字节,也就是 24 bit。- 单个码点
😀在 UTF-8 中是 4 个字节,也就是 32 bit。
这就是“汉字为什么不是 8 个 bit”的直接答案:UTF-8 并没有规定一个字符只能使用一个字节。 8 bit 只有 256 种组合,显然不足以直接覆盖 Unicode 中的大量文字和符号。
还要注意一个更严格的细节:用户眼中的“一个字符”也不一定只对应一个 Unicode 码点。例如某些带组合符号的文字和 emoji 序列会由多个码点组成,因此它们在 UTF-8 中可能超过 4 个字节。本文中的 😀 是单一码点示例。
一个字符不等于一个字节
“character = byte”只在很有限的场景下成立。以 UTF-8 为例:
- 基础 ASCII 字符通常占 1 字节;
- 很多欧洲文字会占 2 字节;
- 常见汉字通常占 3 字节;
- U+10000 以上的码点(例如
😀)占 4 字节。
因此,按“字符数”截断 UTF-8 数据时,不能简单按字节数切。反过来,看到一串二进制也不能只按每 8 bit 直接猜字符,还必须知道这些字节采用了什么编码。
从输入到保存,实际发生了什么
以输入一个汉字为例,过程通常比“按键 → ASCII”复杂得多,尤其是中文输入法参与时。更合理的简化流程是:
- 键盘和输入法把用户操作转换成程序能够处理的字符。
- 应用程序内部用某种 Unicode 表示来处理这些字符。
- 保存文件或发送网络数据时,程序选择具体编码,例如 UTF-8。
- 编码器把 Unicode 码点转换成字节。
- 存储设备和网络传输处理的是这些字节;需要展示文本时,再按同一种编码解码回来。
如果编码和解码使用了不同规则,就可能出现问号、替换字符或错误文字。这是编码不匹配,并不等于数据被“加密”了。
编码、压缩、加密是三件不同的事
这三个概念经常被混在一起:
| 概念 | 目的 | 例子 |
|---|---|---|
| 编码(encoding) | 按约定把字符或数据表示成另一种形式 | Unicode 码点通过 UTF-8 变成字节 |
| 压缩(compression) | 减少数据体积,之后可以解压恢复 | ZIP、gzip、RLE |
| 加密(encryption) | 在没有密钥时隐藏原始内容 | AES、ChaCha20 |
例如连续的 AAAAAA 可以用类似 RLE(游程编码)的思路记录成“6 个 A”这样的“次数 + 值”结构,但这属于压缩,不是 ASCII 或 UTF-8 本身的规则。未压缩时,这 6 个 A 在 UTF-8 中仍然是 6 个 41 字节。
同样,加密后的结果叫密文(ciphertext)。密文可能看起来无法直接阅读,但不应该把它简单称为“乱码”。编码只是表示方式,二进制表示本身也不提供保密性。
如何把文本转换成二进制
如果已经确定使用 UTF-8,转换步骤就很清楚:
- 取得字符对应的 Unicode 码点。
- 用 UTF-8 把码点编码成字节。
- 把每个字节写成 8 位二进制。
例如 中:
- Unicode 码点:U+4E2D
- UTF-8 字节:
E4 B8 AD - 二进制:
11100100 10111000 10101101
这里真正决定二进制结果的是 UTF-8 字节序列。换一种编码,同一个字符得到的字节可能不同。
自己验证
你可以直接用站内工具检查结果:
实际调试文本问题时,建议同时查看十六进制字节。相比一长串 0 和 1,E4 B8 AD 这样的写法更容易核对 UTF-8 边界。
记住这条关系就够了
理解文本与二进制,不需要把“计算机只懂 0 和 1”当作全部答案。更准确的关系是:
字符 → Unicode 码点 → UTF-8 等编码产生的字节 → 每个字节由 bit 表示。
只要把这四层分开,就能解释为什么 A 是 1 个 UTF-8 字节、中 是 3 个字节、😀 是 4 个字节,也能避免把编码、压缩和加密混为一谈。