文章目录

  • hex
  • uu
  • base64
  • qp


binascii顾名思义用于二进制和ASCII之间的转换,主要提供了hex, uu, base64, qp, hqx五种编解码方式。其函数名称为a2b_xx或者b2a_xxxx替换成不同的编码方式。

hex

其中hex即十六进制字符串。在python中其实存在一个将数值转为十六进制字符串的函数hex

>>> hex(15)
'0xf'

而在binascii中,输入为二进制字符串,尤其对于a2b函数而言,输入的是ASCII编码的二进制字符串。

from binascii
>>> test = b'test'  #此为ASCII编码的二进制数据
>>> print(test)
b'test'
>>> b2a_hex(test)
#在ASCII中,tes分别对应十六进制的74, 65, 73,
b'74657374'
>>> a2b_hex(test)
# 报错了,因为十六进制字符串中没有`tes`这几个值
binascii.Error: Non-hexadecimal digit found
>>> a2b_hex(b'74657374')
b'test'

由于ASCII的128个字符中,并非所有字符都是可打印的,就是说无法完整地显示所有的二进制数据,故而很多时候需要用到十六进制来表示。

但十六进制中基本的字符只有16个,原本需要用一个字节打印的ASCII,如果用十六进制表示,则需要2个字节,相对来说编码效率是很低的。

所以人们发明了其他高效的编码形式。

uu

ASCII总共有128个字符,但可打印字符并不多,只有100个,而且这100个里面还包括回车之类的字符。

>>> import string
>>> string.printable
'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'
>>> len(string.printable)
100 #100个可打印字符 可用的大概有90
>>>

而一个字节的长度为8,包含256种不同的二进制组合,则3个字节包含16777216种组合方式。若从可打印字符种抽出64个,那么就可以用4个字节的可打印字符,来表示3个字节二进制数据。

uu编码就是采用这种思路,其中uu即Unix-to-Unit。其编码过程为:

  1. 将输入的3个字节(3x8=24bit),平均分为4份(24/4=6bit),则每份有6bit。
  2. 将6bit数据转为数值后,加上0x20,从而使得所有数据落入0x20-0x5F中。
  3. 优势考虑到0x20对应的是空格,所以将0x20转为0x60,但显然b2a_uu是没考虑到的。
>>> test = b'\x01\x10\x11'
>>> b2a_uu(test)
b'# 1 1\n'

其中输入为b'\x01\x10\x11',拆分成二进制为000000 010001 000000 010001,转为十进制即0, 17, 0, 17,再加上0x20,即加上32,分别得到32,49,32,49,32和49分别对应ASCII中的空格1

可见b2a_uu#开头,以\n结束。

a2b_uu为其反函数。

base64

base64也是3字节变4字节,但并不加0x20,而是另外做了一个码表。其中,[0,25]对应A-Z,[26,51]对应a-z,[52,61]对应0-9,最后62、63分别对应+/

所以0对应的是A,17对应的是R

>>> b2a_base64(test)
b'ARAR\n'

hqx也是三字节转4字节,据说与苹果系统有关,编码方式过于高深莫测,不像是正常人能想出来的方案,有兴趣的可以自己去查一下对应的码表。

qp

qp即Quoted-Printable,方法是将可打印字符和不可打印字符分开。对于输入数据在33-60、62-126范围内的,可以直接输出;其他值则编码为=与2位大写的Hex码。之所以60和62中间断开了,乃因61位是=

所以很不幸0和17都不在可打印区间

>>> b2a_qp(test)
b'=01=10=11'
>>> b2a_qp(b"abc=")
b'abc=3D'