BaseX编码规则解析

一、Base16

1.1、编码规则:

Base16编码使用16ASCII可打印字符(数字0-9和字母A-F)对任意字节数据进行编码。

  • 获取输入字符串每个字节的二进制值(输入的非ASCII字符,使用UTF-8字符集);

  • 将获得的二进制值串联进来;

  • 按照4比特为一组进行切分(8比特数据按照4比特切分刚好是两组,因此Base16无填充符号=);

  • 将每组二进制数分别转换成十进制;

  • 按照Base16对应的编码表将对应的编码串接起来就是Base16编码;

1.2、编码特征

Base16编码后的数据量是原数据的两倍,1000比特数据需要250个字符(即 250*8=2000 比特)。换句话说:Base16使用两个ASCII字符去编码原数据中的一个字节数据。

Base16编码是一个标准的十六进制字符串(注意是字符串而不是数值),更易被人类和计算机使用,因为它并不包含任何控制字符,以及Base32Base64中的=符号。

1.3、编码表

编码 编码
0 0 8 8
1 1 9 9
2 2 10 A
3 3 11 B
4 4 12 C
5 5 13 D
6 6 14 E
7 7 15 F

1.4、编码示例

  • 待编码字符串:123
  • 编码后字符串:313233
原始字符(ASCII可显示字符) 对应二进制(对应两个) 对应编码后字符串
1 0011 0001 31
2 0011 0010 32
3 0011 0011 33

二、Base32

2.1、编码规则

Base32编码是使用32ASCII可打印字符(字母A-Z和数字2-7)对任意字节数据进行编码。

  • 获取输入字符串每个字节的二进制值(输入的非ASCII字符,使用UTF-8字符集);

  • 将获得的二进制值串联进来;

  • 按照5比特为一组进行切分;

  • 将每组二进制数分别转换成十进制;

  • 按照Base32对应的编码表将对应的编码串接起来就是Base32编码;

2.2、编码特征

  • 数据的二进制传输是按照8比特一组进行(即一个字节);
  • Base325比特切分的二进制数据必须是40比特的倍数(5和8的最小公倍数),最小为40个比特
  • 编码后的字符串不用区分大小写并排除了容易混淆的字符,可以方便地由人类使用并由计算机处理;

与Base64相比,Base32具有许多优点:

  • 适合不区分大小写的文件系统,更利于人类口语交流或记忆;
  • 结果可以用作文件名,因为它不包含路径分隔符 “/”等符号;
  • 排除了视觉上容易混淆的字符,因此可以准确的人工录入(例如,RFC4648符号集忽略了数字“1”、“8”和“0”,因为它们可能与字母“I”,“B”和“O”混淆);
  • 排除填充符号“=”的结果可以包含在URL中,而不编码任何字符;

与Base16相比,Base32的优势:

  • Base32比Base16占用的空间更小(1000比特数据Base32需要200个字符,而Base16则为250个字符);

Base32的缺点:

  • Base32比Base64多占用大约20%的空间,因为Base32使用8个ASCII字符去编码原数据中的5个字节数据,而Base64是使用4个ASCII字符去编码原数据中的3个字节数据;

2.3、编码表

编码 编码 编码 编码
0 A 8 I 16 Q 24 Y
1 B 9 J 17 R 25 Z
2 C 10 K 18 S 26 2
3 D 11 L 19 T 27 3
4 E 12 M 20 U 28 4
5 F 13 N 21 V 29 5
6 G 14 O 22 W 30 6
7 H 15 P 23 X 31 7
填充 =

2.4、编码示例

  • 待编码字符串:123
  • 编码后字符串:GEZDG===
原始字符(ASCII可显示字符) 对应二进制(对应两个)
1 0011 0001
2 0011 0010
3 0011 0011
  • 拼接后的二进制:00110001 00110010 00110011
  • 按照5比特进行拆分:00110 00100 11001 00011 0011
  • 最后一组的位数不足5,末位填充0后:00110 00100 11001 00011 00110
  • 对应字符串位:GEZDG
  • 由于最少为40个比特,计算40/5=8,因此需要补3=,最终为GEZDG===

三、Base64

3.1、编码规则

Base64编码是使用64ASCII可打印字符(A-Za-z0-9+/)对任意字节数据进行编码。

  • 获取输入字符串每个字节的二进制值(若不足8比特则高位补0);

  • 将获得的二进制值串联进来;

  • 按照6特为一组进行切分;

  • 将每组二进制数分别转换成十进制;

  • 按照Base64对应的编码表将对应的编码串接起来就是Base64编码;

由于二进制数据是按照8比特一组进行传输,因此Base64按照6比特一组切分的二进制数据必须是24比特的倍数(6和8的最小公倍数),24比特就是3个字节,若原字节序列数据长度不是3的倍数时:

  • 原字节序列剩下1个输入数据,则在编码结果后加1个=

  • 原字节序列剩下2个输入数据,则在编码结果后加2个=

3.2、编码特征

完整的Base64定义可见RFC1421RFC2045。因为Base64算法是将3个字节原数据编码为4个字节新数据,所以Base64编码后的数据比原始数据略长,为原来的4/3。在电子邮件中,根据RFC822规定,每76个字符,还需要加上一个回车换行。可以估算编码后数据长度大约为原长的135.1%

Base64可用于任意数据的底层二进制数据编码,以应用于只能传输ASCII字符的场合。不过最常用于文本数据的处理传输,例如在MIME格式的电子邮件中,Base64可以用来编码邮件内容,方便在不同语言计算机间传输而不乱码,注意是传输而不是显示,例如在西欧地区计算机上使用UTF-8编码即可正常显示中文(安装有对应字库),但是它未必能正常传输中文,这时转换为Base64便无此顾虑。

Base64编码若无特别说明,通常约定非ASCII字符按照UTF-8字符集进行编码处理。

3.3、编码表

编码 编码 编码 编码
0 A 16 Q 32 g 48 w
1 B 17 R 33 h 49 x
2 C 18 S 34 i 50 y
3 D 19 T 35 j 51 z
4 E 20 U 36 k 52 0
5 F 21 V 37 l 53 1
6 G 22 W 38 m 54 2
7 H 23 X 39 n 55 3
8 I 24 Y 40 o 56 4
9 J 25 Z 41 p 57 5
10 K 26 a 42 q 58 6
11 L 27 b 43 r 59 7
12 M 28 c 44 s 60 8
13 N 29 d 45 t 61 9
14 O 30 e 46 u 62 +
15 P 31 f 47 v 63 /

3.4、编码示例

  • 待编码字符串:1234
  • 编码后字符串:MTIzNA==
原始字符(ASCII可显示字符) 对应二进制(对应两个)
1 00110001
2 00110010
3 00110011
4 00110100
  • 拼接后的二进制:00110001 00110010 00110011 00110100
  • 按照6比特进行拆分:001100 010011 001000 110011 001101 00
  • 最后一组的位数不足5,末位填充0后:001100 010011 001000 110011 001101 000000
  • 对应编码表的字符串:MTIzNA
  • 原字节序列的长度为4,不为3的倍数,还差2个输入数据,所以需要补上2个=,最终为:MTIzNA==

四、Base58

4.1、编码规则

Base58编码使用58ASCII可打印字符(不使用数字0,大写字母O、大写字母I、小写字母l,以及+/)对 数字 进行编码。

  • 通过对数字不断取余58,依据获取的余数对照编码表得到对应的编码值;
  • 通过不断的对数字进行取整操作,得到新的数字进入下一个循环;
  • 当新的数字为0时,结束编码;
  • 通过对循环中每次得到的编码按照得到的先后顺序逆序排序(即第一次得到的编码在最终编码值的末尾),得到最终的编码值;

4.2、编码特征

  • 在某些字体下,数字0字母大写O,以及字母大写I字母小写l会非常相似,为避免混淆,不使用这些字符;
  • 不使用+/的原因是非字母或数字的字符串作为帐号较难被接受;
  • 没有标点符号,通常不会被从中间分行;
  • 大部分的软件支持双击选择整个字符串;
  • 编码后的数据为原始的数据长度的1.37倍,稍稍多于Base64的1.33倍;
  • 用于Bitcoin中使用的一种独特的编码方式,主要用于产生Bitcoin的钱包地址;

4.3、编码表

编码 编码 编码 编码
0 1 15 G 30 X 45 n
1 2 16 H 31 Y 46 o
2 3 17 J 32 Z 47 p
3 4 18 K 33 a 48 q
4 5 19 L 34 b 49 r
5 6 20 M 35 c 50 s
6 7 21 N 36 d 51 t
7 8 22 P 37 e 52 u
8 9 23 Q 38 f 53 v
9 A 24 R 39 g 54 w
10 B 25 S 40 h 55 x
11 C 26 T 41 i 56 y
12 D 27 U 42 j 57 z
13 E 28 V 43 k
14 F 29 W 44 m

4.4、编码示例

  • 待编码数字:123
  • 编码后字符串:38

解析过程如下所示:

  • 对数字进行取余58的操作,获取余数:123%58=7,得到第一个编码为8
  • 对数字进行取整操作,新的数字为取整之后的值:123/58=2
  • 对新数字进行取余58的操作,获取余数:2%58=2,得到第二个编码为3
  • 依次循环最终新数字为0时结束;
  • 最后得到的编码为38

五、Base62

5.1、编码规则

Base62编码使用62ASCII可打印字符(数字0~9,字母A~Za~z)进行编码。

  • 通过对数字不断取余62,依据获取的余数对照编码表得到对应的编码值;
  • 通过不断的对数字进行取整操作,得到新的数字进入下一个循环;
  • 当新的数字为0时,结束编码;
  • 通过对循环中每次得到的编码按照得到的先后顺序逆序排序(即第一次得到的编码在最终编码值的末尾),得到最终的编码值;

5.2、编码特征

  • Base62Base64相比唯一的区别就是少了两个特殊符号;
  • Base62是一个改掉了Base64所有缺点的算法;
  • 唯一的不足是因为码空间小了,会多占用1/32空间;
  • 常被用来做短url的映射;

5.3、编码表

编码 编码 编码 编码
0 0 16 G 32 W 48 m
1 1 17 H 33 X 49 n
2 2 18 I 34 Y 50 o
3 3 19 J 35 Z 51 p
4 4 20 K 36 a 52 q
5 5 21 L 37 b 53 r
6 6 22 M 38 c 54 s
7 7 23 N 39 d 55 t
8 8 24 O 40 e 56 u
9 9 25 P 41 f 57 v
10 A 26 Q 42 g 58 w
11 B 27 R 43 h 59 x
12 C 28 S 44 i 60 y
13 D 29 T 45 j 61 z
14 E 30 U 46 k
15 F 31 V 47 l

5.4、编码示例

  • 待编码数字:123
  • 编码后字符串:1z

解析过程如下所示:

  • 对数字进行取余62的操作,获取余数:123%62=61,得到第一个编码为z
  • 对数字进行取整操作,新的数字为取整之后的值:123/62=1
  • 对新数字进行取余62的操作,获取余数:1%62=1,得到第二个编码为1
  • 依次循环最终新数字为0时结束;
  • 最后得到的编码为1z

六、Base85

Base85又叫ASCII85,是Paul E. Rutterbtoa程序开发的一种二进制文本编码方式。

6.1、编码规则

Base85编码使用85ASCII可打印字符(数字0~9,字母A~Za~u,和一些其他字符)进行编码。

  • 4个ASCII字符一组(如果最后的不够4个ASCII字符,右面填充二进制全0),从左到右拼接这4个ASCII对应的二进制的值,将该二进制转为十进制
  • 将得到的十进制数字对58取余操作,得到第一个关键数字;
  • 将得到的十进制数字对58取整操作,得到新的十进制数字;
  • 使用新的十进制数字再次对58进行取余操作,依次得到新的关键数字,直到取整的结果为0
  • 将最终得到的关键数字排序后(按照得到数字的先后,从右向左排序);
  • 参考Base85的编码表得到编码后的字符序列,细心点会发现,得到的关键数字加上33的话,也是对应的ASCII的值;
  • 编码后的数据中包含像反斜杠引用等转义字符也是Base85的缺点之一,因为这些字符在一些编程语言或基于文本的协议中有特殊的含义;

6.2、编码特征

  • 利用5个ASCII字符来表示4字节的数据,如果每个ASCII字符占用8比特,则编码后的数据比原始数据大长度增加1/4
  • UUENCODEBase64编码方式更加高效;
  • Base85Adobe’s PostScriptPortable Document Format(PDF)的主要编码模块;
  • 4字节可以表示2^32=4294967296个可能的值,而85^5=4437053125个可能的值,这就可以代表所有32bit的值,85^4可以表示4182119424个数值,所以85的5次方是基于5个ASCII字符表示4byte的最好且最小选择;

6.3、编码表

编码 编码 编码 编码
0 ! 22 7 44 M 66 c
1 " 23 8 45 N 67 d
2 # 24 9 46 O 68 e
3 $ 25 : 47 P 69 f
4 % 26 ; 48 Q 70 g
5 & 27 < 49 R 71 h
6 28 = 50 S 72 i
7 ( 29 > 51 T 73 j
8 ) 30 ? 52 U 74 k
9 * 31 @ 53 V 75 l
10 + 32 A 54 W 76 m
11 , 33 B 55 X 77 n
12 - 34 C 56 Y 78 o
13 . 35 D 57 Z 79 p
14 / 36 E 58 [ 80 q
15 0 37 F 59 \ 81 r
16 1 38 G 60 ] 82 s
17 2 39 H 61 ^ 83 t
18 3 40 I 62 _ 84 u
19 4 41 J 63 `
20 5 42 K 64 a
21 6 43 L 65 b

6.4、编码示例

  • 待编码字符串:sure
  • 编码后字符串:F*2M7

解析过程如下所示:

  • 字符串sure的每位字符对应的ASCII的十进制分别为:115117114101
  • 将十进制转换为二进制,得到的二进制序列为:01110011 01110101 01110010 01100101
  • 该二进制拼接起来后对应的十进制数字为:1937076837
  • 对该十进制数字进行循环的取余/整操作,按照先后顺序依次得到的余数分别为:224417937
  • 参考Base85的编码表,对应的编码值分别为:7M2*F
  • 按照得到的余数的先后顺序逆序排列后得到最终的编码值为:F*2M7

七、Base91

Joachim Henke在2005年发明,官方的介绍页面为:basE91 encoding

7.1、编码规则

加密使用类似于Base64的方法,但将字母扩展为91个字符:94个可打印的ASCII字符(从0x210x7E),省略了-\';为了简化,将数据分为13位二进制数据包(即2^13=8192个值),然后将其编码为2个字母(包含91个字符,其中91^2=8281);

  • 将输入的数据看作二进制信息流;
  • 每次从信息流中读取13位的比特数据,将这组合成的13位比特转换为10进制的整数;
  • 如果该整数小于或等于88,则额外再读取一位,并将这一位放在整数的第14位(最低位为1)(原因:由于91^2=8281,最大可表示为8280,而2^13=8192,因此即使二进制13位全部为1,也可能);
  • 将得到的整数拆分为两个编码值,第一个编码值为整数%91,第二个编码值为整数/91,依据Base91的编码表得到对应的编码后的数据;
  • 依次循环编码接下来的二进制信息流;

7.2、编码特征

  • 该算法相对于Base64来说比较复杂,但更节省空间;
  • Base64不同,输出的大小有点依赖于输入字节,长度为0x00n序列短于长度为0xFFn序列(其中n是足够大的数字);

7.3、编码表

编码 编码 编码 编码
0 A 23 X 46 u 69 *
1 B 24 Y 47 v 70 +
2 C 25 Z 48 w 71 ,
3 D 26 a 49 x 72 .
4 E 27 b 50 y 73 /
5 F 28 c 51 z 74 :
6 G 29 d 52 0 75 ;
7 H 30 e 53 1 76 <
8 I 31 f 54 2 77 =
9 J 32 g 55 3 78 >
10 K 33 h 56 4 79 ?
11 L 34 i 57 5 80 @
12 M 35 j 58 6 81 [
13 N 36 k 59 7 82 ]
14 O 37 l 60 8 83 ^
15 P 38 m 61 9 84 _
16 Q 39 n 62 ! 85 `
17 R 40 o 63 # 86 {
18 S 41 p 64 $ 87 |
19 T 42 q 65 % 88 }
20 U 43 r 66 & 89 ~
21 V 44 s 67 ( 90 "
22 W 45 t 68 )

7.4、编码示例

  • 待编码字符串:abc
  • 编码后字符串:#G(I

解析过程如下所示:

  • 字符串abc的每位字符对应的ASCII十进制分别为:979899
  • 十进制转换为二进制,得到的二进制序列为:01100001 01100010 01100011
  • 读取该二进制信息流之后,得到的第一个二进制串为:00010 01100001,该二进制串的后半部分为字符a二进制编码,前半部分为字符b的部分二进制编码;
  • 拼接后的二进制串对应的十进制整数为:609,因此首先得到的两个编码值为:609%91=63609/91=6,对应的编码为:#G
  • 继续处理剩余的二进制序列为:00 01100011 011,对应得到的十进制整数为:795,因此得到的两个编码值为:795%91=67795/91=8,对应的编码为:(I
  • 因此最终得到的最终编码为:#G(I

八、Base X(2~36)

BaseX(2~36),其中X可以为2~36的所有编码规则完全一致,这里以Base36为例作一下详细介绍。

8.1、编码规则

Base36编码使用36ASCII可打印字符(数字0-9和字母A-Z)对数字进行编码。

  • 通过对数字不断取余36,依据获取的余数对照编码表得到对应的编码值;
  • 通过不断的对数字进行取整操作,得到新的数字进入下一个循环;
  • 当新的数字为0时,结束编码;
  • 通过对循环中每次得到的编码按照得到的先后顺序逆序排序(即第一次得到的编码在最终编码值的末尾),得到最终的编码值;

8.2、编码特征

  • Base 36的编码规则不同于Base 16/32/64,它无法按照比特范围进行编码操作,需要按照取余/整的不断操作,经过与编码表的对应获得最终的编码值;
  • 对于字符串的相关编码操作,需要将String的字符串转换为基数为2~36的无符号长整型,再进行编码操作;
  • 有符号的32位整数最大值Base36编码为:ZIK0ZJ
  • 有符号的64位整数最大值Base36编码为:1Y2P0IJ32E8E7

8.3、编码表

编码 编码 编码
0 0 12 C 24 O
1 1 13 D 25 P
2 2 14 E 26 Q
3 3 15 F 27 R
4 4 16 G 28 S
5 5 17 H 29 T
6 6 18 I 30 U
7 7 19 J 31 V
8 8 20 K 32 W
9 9 21 L 33 X
10 A 22 M 34 Y
11 B 23 N 35 Z

8.4、编码示例

  • 待编码数字:123
  • 编码后字符串:3F

解析过程如下所示:

  • 对数字进行取余36的操作,获取余数:123%36=15,得到第一个编码为F
  • 对数字进行取整操作,新的数字为取整之后的值:123/36=3
  • 对新数字进行取余36的操作,获取余数:3%36=3,得到第二个编码为3
  • 依次循环最终新数字为0时结束;
  • 最后得到的编码为3F

九、ASCII字符表

9.1、ASCII可显示字符

二进制 十进制 十六进制 字符 二进制 十进制 十六进制 字符 二进制 十进制 十六进制 字符
00100000 32 0x20 空格 01000000 64 0x40 @ 01100000 96 0x60 `
00100001 33 0x21 ! 01000001 65 0x41 A 01100001 97 0x61 a
00100010 34 0x22 " 01000010 66 0x42 B 01100010 98 0x62 b
00100011 35 0x23 # 01000011 67 0x43 C 01100011 99 0x63 c
00100100 36 0x24 $ 01000100 68 0x44 D 01100100 100 0x64 d
00100101 37 0x25 % 01000101 69 0x45 E 01100101 101 0x65 e
00100110 38 0x26 & 01000110 70 0x46 F 01100110 102 0x66 f
00100111 39 0x27 01000111 71 0x47 G 01100111 103 0x67 g
00101000 40 0x28 ( 01001000 72 0x48 H 01101000 104 0x68 h
00101001 41 0x29 ) 01001001 73 0x49 I 01101001 105 0x69 i
00101010 42 0x2A * 01001010 74 0x4A J 01101010 106 0x6A j
00101011 43 0x2B + 01001011 75 0x4B K 01101011 107 0x6B k
00101100 44 0x2C , 01001100 76 0x4C L 01101100 108 0x6C l
00101101 45 0x2D - 01001101 77 0x4D M 01101101 109 0x6D m
00101110 46 0x2E . 01001110 78 0x4E N 01101110 110 0x6E n
00101111 47 0x2F / 01001111 79 0x4F O 01101111 111 0x6F o
00110000 48 0x30 0 01010000 80 0x50 P 01110000 112 0x70 p
00110001 49 0x31 1 01010001 81 0x51 Q 01110001 113 0x71 q
00110010 50 0x32 2 01010010 82 0x52 R 01110010 114 0x72 r
00110011 51 0x33 3 01010011 83 0x53 S 01110011 115 0x73 s
00110100 52 0x34 4 01010100 84 0x54 T 01110100 116 0x74 t
00110101 53 0x35 5 01010101 85 0x55 U 01110101 117 0x75 u
00110110 54 0x36 6 01010110 86 0x56 V 01110110 118 0x76 v
00110111 55 0x37 7 01010111 87 0x57 W 01110111 119 77 w
00111000 56 0x38 8 01011000 88 0x58 X 01111000 120 0x78 x
00111001 57 0x39 9 01011001 89 0x59 Y 01111001 121 0x79 y
00111010 58 0x3A : 01011010 90 0x5A Z 01111010 122 0x7A z
00111011 59 0x3B ; 01011011 91 0x5B [ 01111011 123 0x7B {
00111100 60 0x3C < 01011100 92 0x5C \ 01111100 124 0x7C |
00111101 61 0x3D = 01011101 93 0x5D ] 01111101 125 0x7D }
00111110 62 0x3E > 01011110 94 0x5E ^ 01111110 126 0x7E ~
00111111 63 0x3F ? 01011111 95 0x5F _

9.2、ASCII控制字符

二进制 十进制 十六进制 缩写 名称/意义
0000 0000 0 0x0 NUL 空字符(Null)
0000 0001 1 0x1 SOH 标题开始
0000 0010 2 0x2 STX 本文开始
0000 0011 3 0x3 ETX 本文结束
0000 0100 4 0x4 EOT 传输结束
0000 0101 5 0x5 ENQ 请求
0000 0110 6 0x6 ACK 确认回应
0000 0111 7 0x7 BEL 响铃
0000 1000 8 0x8 BS 退格
0000 1001 9 0x9 HT 水平定位符号
0000 1010 10 0x0A LF 换行键
0000 1011 11 0x0B VT 垂直定位符号
0000 1100 12 0x0C FF 换页键
0000 1101 13 0x0D CR 归位键
0000 1110 14 0x0E SO 取消变换(Shift out)
0000 1111 15 0x0F SI 启用变换(Shift in)
0001 0000 16 0x10 DLE 跳出数据通讯
0001 0001 17 0x11 DC1 设备控制一(XON 启用软件速度控制)
0001 0010 18 0x12 DC2 设备控制二
0001 0011 19 0x13 DC3 设备控制三(XOFF 停用软件速度控制)
0001 0100 20 0x14 DC4 设备控制四
0001 0101 21 0x15 NAK 确认失败回应
0001 0110 22 0x16 SYN 同步用暂停
0001 0111 23 0x17 ETB 区块传输结束
0001 1000 24 0x18 CAN 取消
0001 1001 25 0x19 EM 连接介质中断
0001 1010 26 0x1A SUB 替换
0001 1011 27 0x1B ESC 跳出
0001 1100 28 0x1C FS 文件分割符
0001 1101 29 0x1D GS 组群分隔符
0001 1110 30 0x1E RS 记录分隔符
0001 1111 31 0x1F US 单元分隔符
0111 1111 127 0x7F DEL 删除

十、在线编码网站

Author: bugwz
Link: https://bugwz.com/2019/11/18/baseX/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.