Base系列编码浅析【base16 base32 base64 base85 base36 base 58 base91 base 92 base62】

Base系列编码浅析

【base16   base32   base64   base85  base36  base 58  base91  base 92   base62】

 
 
base编码有不少种
 
经常使用的有:
 
base16   base32   base64   base85  base36  base 58  base91  base 92   base62
 

 

Base16

 
Base16编码使用16个ASCII可打印字符(数字0-9和字母A-F)对任意字节数据进行编码。
Base16先获取输入字符串每一个字节的二进制值(不足8比特在高位补0),而后将其串联进来,再按照4比特一组进行切分,将每组二进制数分别转换成十进制。
 
                                    
 
注:能够看到8比特数据按照4比特切分恰好是两组,因此Base16不可能用到填充符号“=”。
 
Base16编码后的数据量是原数据的两倍:1000比特数据须要250个字符(即 250*8=2000 比特)。
换句话说:Base16使用两个ASCII字符去编码原数据中的一个字节数据。
Base16编码是一个标准的十六进制字符串(注意是字符串而不是数值),更易被人类和计算机使用,由于它并不包含任何控制字符,以及Base64和Base32中的“=”符号。
 
 

 
 

Base32

 
Base32编码是使用32个可打印字符(字母A-Z和数字2-7)对任意字节数据进行编码的方案,编码后的字符串不用区分大小写并排除了容易混淆的字符,能够方便地由人类使用并由计算机处理。 Base32主要用于编码二进制数据,可是Base32也可以编码诸如ASCII之类的二进制文本。
 
 
 
Base32将任意字符串按照字节进行切分,并将每一个字节对应的二进制值(不足8比特高位补0)串联起来,按照5比特一组进行切分,并将每组二进制值转换成十进制来对应32个可打印字符中的一个。
 
因为数据的二进制传输是按照8比特一组进行(即一个字节),所以Base32按5比特切分的二进制数据必须是40比特的倍数(5和8的最小公倍数)。例如输入单字节字符“%”,它对应的二进制值是“100101”,前面补两个0变成“00100101”(二进制值不足8比特的都要在高位加0直到8比特),从左侧开始按照5比特切分红两组:“00100”和“101”,后一组不足5比特,则在末尾填充0直到5比特,变成“00100”和“10100”,这两组二进制数分别转换成十进制数,经过上述表格便可找到其对应的可打印字符“E”和“U”,可是这里只用到两组共10比特,还差30比特达到40比特,按照5比特一组还需6组,则在末尾填充6个“=”。填充“=”符号的做用是方便一些程序的标准化运行,大多数状况下不添加也可有可无,并且,在URL中使用时必须去掉“=”符号。
 

 

Base64

Base64是一种基于64个可打印字符来表示二进制数据的表示方法。因为 ,因此每6个比特为一个单元,对应某个可打印字符。3个字节有24个比特,对应于4个Base64单元,即3个字节可由4个可打印字符来表示。
它可用来做为电子邮件的传输编码。在Base64中的可打印字符包括字母A-Z、a-z、数字0-9,这样共有62个字符,此外两个可打印符号在不一样的系统中而不一样。一些如uuencode的其余编码方法,和以后BinHex的版本使用不一样的64字符集来表明6个二进制数字,可是不被称为Base64。
 
 
Base64经常使用于在一般处理文本数据的场合,表示、传输、存储一些二进制数据,包括MIME的电子邮件及XML的一些复杂数据。
 
 
 
 
若是要编码的字节数不能被3整除,最后会多出1个或2个字节,那么可使用下面的方法进行处理:
 
先使用0字节值在末尾补足,使其可以被3整除,而后再进行Base64的编码。
 
在编码后的Base64文本后加上一个或两个=号,表明补足的字节数。
 
也就是说:
当最后剩余两个八位(待补足)字节(2个byte)时,最后一个6位的Base64字节块有四位是0值,最后附加上两个等号;
若是最后剩余一个八位(待补足)字节(1个byte)时,最后一个6位的base字节块有两位是0值,最后附加一个等号。 
 
参考下表:
 
 
 
 

 
 
 

Base85

base85 也称为Ascii85,是Paul E. Rutter为btoa实用程序开发的一种二进制文本编码形式。经过使用五个ASCII字符来表示四个字节的二进制数据(使编码量1 / 4比原来大,假设每ASCII字符8个比特),它比更有效UUENCODE或Base64的,它使用四个字符来表示三个字节的数据(1 / 3的增长,假设每ASCII字符8个比特)。
它的主要现代用途是Adobe的PostScript和Portable Document Format文件格式,以及Git使用的二进制文件的补丁编码。
 
与Base64同样,Base85编码的目标是对二进制数据可打印的ASCII字符进行编码。可是它使用了更大的字符集,所以效率更高一些。具体来讲,它能够用5个字符编码4个字节(32位)。
 
摘自wiki介绍的一个例子:
 
 
 

 
 
 

Base36

 
 
Base36是一个二进制到文本编码表示方案的二进制数据以ASCII经过将其转化为一个字符串格式基数 -36表示。选择36十分方便,由于可使用阿拉伯数字 0–9和拉丁字母 A–Z [1](ISO基本拉丁字母)表示数字。
每一个base36位须要少于6位的信息来表示。
 
摘自wiki的一个例子:
 
有符号的32位和64位整数分别最多只能容纳6个或13个base-36位数字(许多base-36位数字可能会使32位和64位整数溢出)。
 
例如,在base-36中,“ 922337203685477575807 ” 的64位带符号整数最大值为“ 1Y2P0IJ32E8E7 ”。
相似地,在base-36中,“ 2147483647 ” 的32位带符号整数最大值为“ ZIK0ZJ ”。
 
(这里没看太懂是怎么转换的,请大佬指教~)
 
用于从BASE10编码BASE36的Python代码
 
def base36encode(integer): 
    chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' 
    
     sign = '-' if integer < 0 else '' 
     integer = abs(integer) 
     result = '' 
 
     while integer > 0: 
         integer, remainder = divmod(integer, 36) 
         result = chars[remainder]+result
 
      return sign+result
 
 
 

 

Base58

 
 
 

 

Base58是用于Bitcoin中使用的一种独特的编码方式,主要用于产生Bitcoin的钱包地址。相比Base64, Base58不使用数字"0",字母大写"O",字母大写"I",和字母小写"l",以及"+"和"/"符号
设计Base58主要的目的是:
  1. 避免混淆。在某些字体下,数字0和字母大写O,以及字母大写I和字母小写l会很是类似。
  2. 不使用"+"和"/"的缘由是非字母或数字的字符串做为账号较难被接受。
  3. 没有标点符号,一般不会被从中间分行。
  4. 大部分的软件支持双击选择整个字符串。
 
 
 
 

 
 
 

Base91

 
 
basE91是将二进制数据编码为ASCII字符的高级方法。 
它相似于UUencode或base64,但效率更高。 basE91产生的开销取决于输入数据。 
它的数量最多为23%(而base64为33%),范围能够下降到14%,一般发生在0字节块上。 
这使得basE91对于经过二进制不安全链接(例如电子邮件或终端线)传输较大的文件很是有用。
 
顾名思义,basE91须要91个字符来表示ASCII编码的二进制数据。 从94个可打印ASCII字符(0x21-0x7E)中,如下三个字符被省略以构建basE91字母:
 
-(破折号,0x2D)
\(反斜杠,0x5C)
'(撇号,0x27)
 
转换表由其他字符组成,以下所示。
 
 

 
 

Base92

 
 
有关Base92的资料实在是不多,可是笔者找到了这一篇博客:
 
https://thenoviceoof.com/blog/projects/base92/
 
如下介绍均摘自这篇博客

 

“  若是您对将二进制信息从一个地方转移到另外一地方一无所知,那么就知道将数据从一个地方转移到另外一地方 可能很危险。就是说,这对您的数据有害:也许您须要在仅用于ASCII文本的通道上传输Blob ,而且全部'\n'以C样式字符串表示的字节都会忽然有一个同级符号'\r'。或者,您的传输层实际上真的真的是以null终止的字符串,而且您刚好在字节边界上连续有8个连续的0位,即便它位于blob中一个32位整数的中间,而且你结束了只有一半您的数据。
 
解决此问题的一种方法是使用base64,它使用全部数字和大写/小写字母字符对数据进行编码(再加上两个,但如今咱们将忽略它们)。如今,您在传输层上尝试解释您的字节时没有任何问题,由于每一个人均可以很好地处理字母数字字符,若是没有,您可能不想使用它们。
固然,使用base64了一段时间后,您可能会注意到,虽然您不会由于一位反复无常的上帝觉得他在提供帮助,却没有按照本身的意愿对数据进行更改,但您却经过使用放弃了效率base64。对于二进制blob中的每3个字节,若是须要传输字母数字字符,则有4个字节,所以您要以33%的容量税来支付数据保护费用:若是暴徒能够在保护球拍中掠走33%,相信他们会的。
看一下base64,您可能会注意到,除了可使用的64个字符外,还有更多可显示的ASCII字符,base64能够在编码中使用这些字符以提升传输密度。这样就base85诞生了,使用了……您猜对了,有85个字符!此次,将4字节的二进制数据编码为5个ASCII字符,这将致使20%的传输大小开销。但你能作什么呢?好像没有更多可显示的ASCII了……哦,等等。
因此彷佛没有人试图超越明显的下一步base85,因此我决定尝试本身作base92。
 
在键入编码的字符串时,`和“与普通引号'太类似,以使其温馨。但愿在区分l / 1和0 / O时使用的字体好。
可是,咱们将〜用做特殊符号(空字符串)。有94个可打印的ascii字符,所以咱们最终获得91个字符,或每一个字符6.5位。一旦包含〜,则将有92个字符:所以,为base92。
(老实说,base91的名字太丑陋了,没法处理)
一旦每一个字符有6.5位,则能够一次使用13位,并使用相似于base85的除法和取模方案,用它们产生两个输出字符。这可能意味着,与base92编码相比,它更能抵抗损坏,由于任何损坏都更加局限(一位更改仅影响2-3个字节,而不影响4个字节)。
注意:在某些须要某些输出的状况下,可能须要将〜用做空字符串分号:可是,传递空字符串进行解码不会致使它变成barf,所以不要求使用〜。
旁注:之前base92产生的输出的长度与输入的长度非单调增加。这已再也不是这种状况。
另外一个旁注:base64和base85更加优雅,将一个较小的字节整数干净地映射到另外一个较小的字节整数。base92将13个字节映射为16个字符,从大小的角度来看,这比base85的4至5个字符更好,可是至关不雅观。
咱们还遵循使用高除数乘积做为第一个字节的base85约定。”
 
 
 

 
 

Base62

 
 
Base62编码将数字转换为ASCII字符串(0-9,az和AZ),反之亦然,这一般会致使字符串较短。
26个小写字母+26个大写字母+10个数字=62
 
 
(1)62进制与10进制的互相转化
 
62进制转10进制与2进制转10进制类似。
2进制转10进制过程为: 从右到左用二进制的每一个数去乘以2的相应次方,次方要从0开始。
62进制转10进制也相似,从右往左每一个数*62的N次方,N从0开始。
 
 
 
那么,10进制转62进制也与10进制转2进制相似。
即:不断除以62取余数,而后倒序。
 
 
(2)关于短Url的转换
 
主要思路,维护一个全局自增的id,每来一个长url,将其与一个自增id绑定,而后利用base62将该自增id转换为base62字符串,即完成转换。

 
 
 
 
 以上就是对Base系列编码的浅析,部分知识是笔者从wiki上搬运过来的,也参考了不少博客文章和资料。若有错误及不足之处,请大佬们多提建议~
 
 
 
 
 
 
参考资料:
 
 
https://en.wikipedia.org/wiki
 
https://blog.csdn.net/n0nameforn0w/article/details/87124053
 
https://thenoviceoof.com/blog/projects/base92/
 
https://segmentfault.com/a/1190000010516708