字符不是字节
计算机存储字节,即 0 到 255 的值。人类阅读字符:字母、数字、标点、表情符号。字符编码是两者之间约定的映射。把映射弄错,你就会看到经典的乱码(café 变成 café),这几乎总是写入字节所用的编码与读取所用的编码之间的不匹配。
ASCII:最初的 128 个
最古老的广泛使用编码是 ASCII,它把数字 0 到 127 分配给基本的英文字母、数字和常见符号。七个比特,128 个字符。ASCII 简单,至今仍是许多计算的底层基础,但 128 个字符无法表示带重音的字母、非拉丁文字或符号,因此它从来不足以表达世界的文字。
Unicode:每个字符一个数字
Unicode 通过给每个字符一个称为码点的唯一数字来解决覆盖问题,写作 U+0041(字母 A)或 U+2615(一种热饮)。Unicode 是一个庞大的字符及其码点目录,远超十万个,基本涵盖每一种在用的文字。
至关重要的是,Unicode 规定每个字符是哪个数字,但不规定如何把那个数字存储为字节。第二项工作属于一种编码形式。
UTF-8:码点如何变成字节
UTF-8 是把 Unicode 码点转换为字节的主流方式,也是整个现代网络的默认。它是变长的:一个字符根据其码点占用一到四个字节。
- ASCII 范围(U+0000 到 U+007F)被编码为单个字节,与 ASCII 相同。这就是为何 UTF-8 向后兼容:任何纯 ASCII 文本本身就是有效的 UTF-8。
- ASCII 之外的字符使用两个、三个或四个字节。因此
é是两个字节,☕是三个,尽管每个都是一个字符。
最后这一点是常见的惊讶之处:一个字符不总是一个字节。 对任何非 ASCII 文本而言,数字节和数字符会给出不同的答案。(UTF-16 和 UTF-32 是同一批码点的替代编码;UTF-8 凭借其 ASCII 兼容性和对拉丁文本的紧凑性赢得了网络。)
Base64 在何处登场
这对 Base64 很重要,因为 Base64 作用于字节,而非字符。 要把一个字符串编码为 Base64,必须先用一种字符编码把字符串变成字节,而那种编码基本上总是 UTF-8。用不同的方案编码同一个字符,你会得到不同的字节,因而得到不同的 Base64。所以文本的完整流水线是:字符变成字节(UTF-8),然后字节变成安全文本(Base64)。解码时,你把两个步骤都倒过来。
Base64 工具 在进行 Base64 编码之前会把文本编码为 UTF-8 字节,并在解码结果不是有效 UTF-8 时予以标记,全部在你的浏览器中。