RUNWEBTOOLS
简体中文
数据格式与编码

字符编码:Unicode 与 UTF-8 详解

更新 2026-07-06

你见过:本该读作 José 的名字变成了 José,或者一个表情符号变成了一堆问号方框。这种乱码有个名字 —— mojibake(文字化け) —— 而它几乎总是字符编码不匹配。本指南讲清字符、Unicode 和 UTF-8 究竟是什么,让这类 bug 不再神秘。

计算机存的是数字,不是字母

在最底层,计算机只存数字(字节)。要存文本,我们需要一张约定好的表,把每个字符映射到一个数字,再映射回来。这张表就是 字符编码。如果一个程序用一张表写文本,另一个程序用另一张表读,数字就会被解读成错误的字符 —— 你就得到乱码。

ASCII:小小的起点

最早广泛使用的编码 ASCII 为 128 个字符定义了数字:英文字母、数字、标点和一些控制码。这对英语够用,但没有位置留给 éüß😀,或世界各语言使用的成千上万个字符。几十年里人人都发明了自己彼此不兼容的扩展,这正是文本在系统之间穿行时会坏掉的原因。

Unicode:为每个字符分配一个数字

Unicode 是通用的解决方案:一个单一标准,为每种书写系统里的每个字符,外加符号和表情符号,分配一个唯一的数字 —— 称为 码点(code point)。码点写作 U+ 后跟一个十六进制数:

A   →  U+0041
é   →  U+00E9
你  →  U+4F60
😀  →  U+1F600

关键在于,Unicode 定义了 数字,但没定义如何把它们存成字节。那是一个单独的决定 —— 而这正是 UTF-8 登场的地方。

UTF-8:Unicode 如何变成字节

UTF-8 是把 Unicode 码点编码成字节的一种方式,也是网络压倒性使用的那种。它精巧的设计在于它是 变长的

  • 128 个 ASCII 字符各占 1 字节 —— 所以 UTF-8 与 ASCII 向后兼容。
  • 大多数带重音的拉丁字符以及希腊/西里尔字符占 2 字节
  • 包括中文、日文和韩文在内的大多数其他文字占 3 字节
  • 表情符号和更罕见的字符占 4 字节

这就是为什么一个“100 字符”的字符串并不总是 100 字节:一个字符可能是好几个字节。它也解释了那个经典的 José bug —— 那是 é 的 UTF-8 字节,被当成较旧的西方编码、一字节一字节地误读了。

字符、码点和字节

三个相关却不同的概念不断让人栽跟头:

  • 字符(Character) —— 人所看到的(字母 é)。
  • 码点(Code point) —— 它的 Unicode 数字(U+00E9)。
  • 字节(Byte) —— 它被存储的方式(在 UTF-8 中,是两个字节 0xC3 0xA9)。

把码点原样写出来看,往往是诊断文本问题最快的办法 —— 例如,一个原来是不换行空格(U+00A0)的“空格”。我们的 Unicode 转换器 会显示任意文本背后的码点,并在字符与转义序列之间转换。

如何避免乱码

  • 到处都用 UTF-8。 把文件保存为 UTF-8 并声明它 —— 在网页上用 <meta charset="utf-8">,在 HTTP 中用 Content-Type 的 charset,在数据库中用 UTF-8 排序规则。
  • 从头到尾保持一致。 大多数损坏发生在一方假设了不同编码的边界处。
  • 为正确的上下文转义。 要把特殊字符安全地放进 HTML,用 HTML 实体;要放进 URL,用 URL 编码

简短版:Unicode 给每个字符一个数字,UTF-8 把这些数字变成字节,而如果人人都同意使用 UTF-8,文本就不再坏掉。

更多 数据格式与编码

查看全部 数据格式与编码 指南 →

本指南提到的工具