自定义字母表编码解码

输入你自己的字母表,或从预设开始修改,然后用它来编码或解码。“大数转换”方式适用于任意长度的字母表,“位分组”方式输出 RFC 4648 风格的结果。

完全在浏览器中运行,不会上传任何数据。

使用方法

  1. 输入字母表,或选择一个预设后再修改。每个字符只能出现一次。
  2. 选择方式:“大数转换”适用于任意长度的字母表,“位分组”适用于 2、4、8、16、32 或 64 个字符的字母表。
  3. 使用按位分组时,可以另外指定一个不在字母表中的填充字符。
  4. 输入文本进行编码,或粘贴用该字母表写成的字符串进行解码。

把字节映射为字符的两种方式

大数方式与 Base58 相同:把整个输入看作一个大整数,反复除以字母表长度,每次的余数决定一个字符。只要字母表至少有 2 个字符就能使用,10、36、58、62 等任意长度都可以。开头的零字节会写成字母表的第一个字符,因此往返转换不会丢失。这种方式没有填充;由于长数据的运算会很慢,输入最多约 20 KB。

按位分组方式与 RFC 4648 相同:把输入切成固定位数的小块,2 个字符的字母表每块 1 位,16 个字符每块 4 位,32 个字符每块 5 位,64 个字符每块 6 位。每一块的值就是字母表中的下标。十六进制、Base32 和 Base64 正是这样工作的,输出长度只取决于输入长度。

为什么两种方式的结果不同

一种方式编码的是数据的数值,另一种方式按位置逐段编码数据的比特。两者的结果通常不同,解码时必须使用编码时的方式。

字母表输入按位分组大数
标准 Base64HiSGk=Ehp
RFC 4648 Base32HiJBUQ====SDJ
01A010000011000001
0123456789Hi不支持18537

使用按位分组并以 = 作为填充字符时,标准字母表得到的就是常规的 Base64 和 Base32。大数方式写出的是数值而不是固定位数,所以 A 开头的那个 0 位被省略了。以十个数字作为字母表时,结果就是 Hi 这两个字节对应的十进制数。

填充字符只对按位分组有效:64 个字符的字母表会把输出补足到 4 的倍数,32 个和 8 个字符的字母表补足到 8 的倍数。2、4、16 个字符的字母表中,每个字节都正好占满整数个字符,因此永远不需要填充。

合法字母表的规则

  • 至少 2 个字符。
  • 不能有重复字符。解码时每个字符必须对应唯一的值。如果 a 同时代表 0 和 10,含有它的字符串就无法解码。
  • 区分大小写。a 和 A 是两个不同的字符。
  • 填充字符不能出现在字母表中,否则无法与数据区分。

编码和解码都在浏览器中进行,字母表和数据都不会离开你的设备。

自定义字母表的用途

  • 混淆 ID。用打乱顺序的字母表,可以把标识符变成看不出规律的字符串。但这只是隐藏,并不安全:知道字母表的人都能解码。
  • 专有或遗留格式。照着系统文档复制它自己的字母表,就能直接解码其中的数据。
  • 学习原理。对比不同长度的字母表和两种方式,直观理解进制转换的原理。固定字母表的编码可以参考 Base58 和 Base62。

常见问题

“大数转换”和“位分组”有什么区别?

大数方式像 Base58 一样,把整个输入当作一个整数转换到新进制,适用于任意长度的字母表。按位分组方式像 Base64 一样,把输入切成固定位数的小块,字母表必须是 2、4、8、16、32 或 64 个字符。

为什么我的自定义 Base64 字母表得不到标准 Base64 的结果?

标准 Base64 使用的是按位分组。选择“位分组”并把填充字符设为 =,结果就会一致。同一个字母表用大数方式会得到完全不同的字符串。

为什么不允许重复字符?

每个字符解码时必须对应唯一的值。重复的字符会有两种含义,原始数据就无法可靠地还原。

大数方式可以使用填充字符吗?

不可以。大数方式的输出没有固定的分组长度,也就无需填充。填充选项只对按位分组有效。

自定义字母表算是加密吗?

不算。它仍然是一种没有密钥的编码。打乱的字母表能让数据不那么容易被一眼认出,但绝不应该用来保护机密信息。