Base 编码是一类把二进制数据映射为可打印字符的表示方法。常见的有 base16、base32、base36、base58、base62、base64、base85、base91、base92 等。它们共享同一套思路:按固定位数切分二进制流,再把每组数值映射到指定字符集;区别在于字符集大小、切分粒度和填充规则。
Base16
使用 16 个可打印字符(0–9 与 A–F)对字节数据编码。把输入按字节展开为二进制(不足 8 位高位补 0)后串联,再以 4 位为一组切分并转成十进制。
编码后长度为原始数据的 2 倍:以 500 字节(4000 比特)的输入为例,编码后恰好是 1000 个字符。
8 位恰好切成两组 4 位,因此 Base16 不需要填充符“=”。
本质是一个标准十六进制字符串(是字符串而非数值),不含控制字符,也不含 Base64/Base32 里的“=”,人类与计算机都易读易处理。
Base32
使用 32 个可打印字符(A–Z 与 2–7)编码任意字节数据。编码结果不区分大小写,并排除了易混淆字符,便于人工识别与机器处理。
主要用途是编码二进制数据,也能编码 ASCII 等二进制文本。
将字节串的二进制值(不足 8 位高位补 0)串联后,以 5 位一组切分,每组转十进制再映射到 32 个字符之一。
由于二进制传输以 8 位(1 字节)为单位,而 Base32 按 5 位切分,故切分后的数据长度必须是 40 比特的倍数(5 与 8 的最小公倍数)。
示例:输入单字节字符 &,其二进制为 100110,高位补 0 得 00100110。从左按 5 位切分00100 与 110;后组不足 5 位,末尾补 0 得 11000。两组分别转十进制后查表得到对应字符。此时仅用 10 比特,距 40 比特还差 30 比特(6 组),故末尾补 6 个“=”。
填充“=”主要用于满足部分程序的标准化处理,多数场景可省略;在 URL 中使用时必须去掉。
Base64
Base64 用 64 个可打印字符表示二进制数据。因 2⁶ = 64,每 6 比特为一个单元,对应一个可打印字符;3 字节(24 比特)对应 4 个 Base64 单元,即 3 字节由 4 个字符表示。
字符集为 A–Z、a–z、0–9 共 62 个,另加两个可打印符号(不同系统可能不同)。
常用作电子邮件的传输编码,也广泛用于在文本场景中表示、传输、存储二进制数据(如 MIME 邮件、XML 中的复杂数据)。
填充规则:若待编码字节数不能被 3 整除,末尾会多出 1 或 2 个字节,处理方式为——
用 0 字节在末尾补足至 3 的倍数,再进行 Base64 编码;
在编码结果后追加一个或两个“=”,表示补足的字节数。
具体地:剩余 2 个字节时,最后一个 6 位块有 4 位为 0,追加两个“=”;剩余 1 个字节时,最后一个 6 位块有 2 位为 0,追加一个“=”。
注:BinHex 使用不同的 64 字符集表示 6 位二进制数,但不称为 Base64。
Base85
Base85(又称 Ascii85)由 Paul E. Rutter 为 btoa 工具开发。它用 5 个 ASCII 字符表示 4 字节二进制数据,相比 Base64(4 字符表示 3 字节)效率更高:Base64 约增加 1/3 体积,Base85 约增加 1/4。
应用场景:Adobe PostScript 与 PDF 文件格式,以及 Git 对二进制文件补丁的编码。
与 Base64 一样面向可打印 ASCII 字符,但字符集更大,因此效率更高——用 5 个字符编码 4 字节(32 位)。
Base36
Base36 是把二进制数据表示为 36 进制字符串的编码方案。选用 36 是因为阿拉伯数字 0–9 与拉丁字母 A–Z 恰好构成 36 个字符,每个 base36 位所需信息少于 6 比特。
有符号 32 位整数最多容纳 6 个 base36 位,64 位整数最多容纳 13 个。
举例来说:一个有符号 32 位整数在 base36 下的表示不会超过 6 个字符,而 64 位整数不会超过 13 个字符。反过来说,用 base36 表示整数时,位数天然有上限,便于预估长度。
Base58
Base58 是 Bitcoin 中使用的编码方式,主要用于生成钱包地址。
相比 Base64,Base58 不使用数字 0、大写 O、大写 I、小写 l,也不使用 + 和 /。
设计动机:
避免混淆:某些字体下 0 与 O、I 与 l 极为相似;
避免非字母数字符号+/ 作为账号字符较难被接受;
无标点:通常不会被从中间分行;
便于选中:多数软件支持双击选中整个字符串。
Base91
basE91 用 91 个字符表示 ASCII 编码的二进制数据。它从 94 个可打印 ASCII 字符(0x21–0x7E)中省略三个字符来构建字母表:
-(破折号,0x2D)
\(反斜杠,0x5C)
'(撇号,0x27)
它是把二进制数据编码为 ASCII 的高级方法,类似 UUencode 或 Base64,但效率更高。开销取决于输入数据:最多约 23%(Base64 为 33%),最低可降到约 14%(常见于全 0 字节块)。因此 basE91 很适合通过二进制不安全的通道(如电子邮件、终端线路)传输较大文件。
Base92
Base92 相对小众,设计思路来自 thenoviceoof 的项目说明,要点如下:
动机:Base64 有约 33% 的体积开销,Base85 约 20%,但可打印 ASCII 字符尚未被充分用尽,于是尝试进一步压缩开销。
字符集:94 个可打印 ASCII 字符中,排除
`和 "(与普通引号 ' 过近),并把 ~ 用作特殊符号(空字符串),最终得到 92 个字符,故称 base92。每字符约 6.5 比特;一次取 13 位,用类似 Base85 的除法取模方案产出两个输出字符。相比 Base85,抗损坏性更好——一位错误只影响 2–3 个字节,而非 4 个字节。
注意:某些需要特定输出的场景可能要求把 ~ 用作空字符串分隔符;但向解码器传入空字符串不会导致异常,因此不强制使用 ~。
早期版本中,base92 输出长度与输入长度并非单调增长,现已修正。
与 Base64、Base85 把较小字节整数干净映射到另一较小字节整数相比,base92 把 13 字节映射为 16 字符,体积上优于 Base85 的 4→5,但不甚优雅。
Base62
Base62 把数字转换为 ASCII 字符串(0–9、a–z、A–Z),反之亦然,通常得到较短的字符串。字符集为 26 个小写字母 + 26 个大写字母 + 10 个数字 = 62。
(1)62 进制与 10 进制互转
62 进制转 10 进制与 2 进制转 10 进制相似:从右往左,每个数乘以 62 的相应次方(次方从 0 开始),再求和。
10 进制转 62 进制则与 10 进制转 2 进制类似:不断除以 62 取余数,最后倒序排列。
(2)短 URL 转换
常见做法是维护一个全局自增 id:每来一个长 URL,就将其与一个自增 id 绑定,再用 Base62 把该 id 转成字符串,即完成短链转换。
结语
以上梳理了 Base 系列常见编码的基本原理与差异。核心无非三点:字符集大小、切分位数、填充规则。理解这三点,各类 Base 编码便不难区分与选用。