前瞻知识
先来了解一下,base64编码是个什么东东啊。官方解释来一波:
可以将任意的字节数组数据,通过算法,生成只有(大小写英文、数字、+、/)(一共64个字符)内容表示的字符串数据。即将任意的内容转换为可见的字符串形式。
学技术的同学对编码大概都有些了解,比如常见的utf-8,gbk等等。那么为什么又搞出来个base64呢,搞心态?显然不是,你得相信,在互联网行业中,无论是网络技术,还是算法技术,还是开发技术,任何一种技术,都有其产生的缘由,都是未解决在技术发展过程中解决某种问题而生的。话不多说
以前发送邮件只支持可见字符的传送。由此,需要有一个方法将不可见的字符转换为可见的字符,便产生了Base64编码算法
OK,了解了这些以后,我们就来探讨一下,base64编码的算法如何:
1、将数据按照 3个字节一组的形式进行处理,每三个字节在编码之后被转换为4个字节。即:如果一个数据有6个字节,可编码后将包含6/3*4=8个字节
2、当数据的长度无法满足3的倍数的情况下,最后的数据需要进行填充操作,即补“=” ,这里“=”是填充字符,不要理解为第65个字符
文字描述莫得感情,上图:
三字节转四字节1
三字节转四字节2
简单来说,将三字节的二进制码转换为二进制流,从流中,依次截取6位可分隔为4段,每一段前补两个零。此时三字节奇妙的被转化为四字节。如果原始数据最后无法凑成3个字节,则补填充,以“=”作为替换,代表没有数据。
下边我们来看看三字节转换为四字节之后,又需要怎么对应b64编码,令人感到十分兴奋的是,并无复杂算法,直接给出索引表,每一位字节转换为十进制之后,对号入座即可
热菜
好了,话不多说,该上热乎乎的代码了。
def base64Encode(string):
oldBin = ""
tempStr = []
result = ""
base64_list = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
# 一共要八位不够补零 得到2进制值的字符串流
for ch in string:
print(ch)
print("{:08}".format(int(str(bin(ord(ch))).replace("0b", ""))))
oldBin += "{:08}".format(int(str(bin(ord(ch))).replace("0b", "")))
# 通过切片将每6位合并得到的字符串放在列表中 {:<06}左对齐 不够补零 主要是为了最后不够6位
for i in range(0, len(oldBin), 6):
tempStr.append("{:<06}".format(oldBin[i:i + 6]))
print(tempStr)
# 每六位 换成十进制 索引到b64列表
for item in tempStr:
result = result + base64_list[int(item, 2)]
# 假如结果不是4的倍数 用等号补齐
if len(result) % 4 == 2:
result += "=="
elif len(result) % 4 == 3:
result += "="
return result
print(base64Encode("AE86"))
此时手快的兄弟大概已经run了,结果大致如下:
结果图这时候就有人要问了,A的二进制是怎么来的,其实是根据A的ASCII码值而来,可以亲手试试,其余同理。那又有人问了,英文的ASCII好说,查个表啥都有。那中文你怎么破。你还别说,我还真遇到坑了,后续再说。现在我们先来逆向思维,从上往下,来解个码。
def base64Decode(string):
result = []
string = string.strip("=")
binstr = ""
bin6list = []
bin8list = []
base64_list = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
# 还原出6位二进制列表
for ch in string:
bin6list.append("{:>06}".format(str(bin(base64_list.index(ch)).replace("0b", ""))))
# 还原出到2进制值的字符串流
binstr = "".join(bin6list)
# 还原出到8位2进制值的字符串列表
for i in range(0, len(binstr), 8):
bin8list.append(binstr[i:i + 8])
# 根据ascall值得出原字符 最后一个item全是多余的0
for item in range(len(bin8list) - 1):
result.append(chr(int(bin8list[item], 2)))
return "".join(result)
print(base64Decode("QUU4Ng=="))
轻轻一run,结果令人舒畅,最后一组零,无需担心,它本就是多余的(编码时补充的)
解码结果
好了,到现在为止,英文我们实现了基本的编码解码,虽然代码粗糙,总归结果令人满意。现在我们来讨论一下中文,接着前文话题,中文的ASCII码怎么解决?python总是考虑的很多。ord方法 用在英文上 返回的是ascii码值,而用在中文上返回的就是 unicode值。没错,完美解决中文编码的时候编码。但是问题还是来了,当你解码的时候,chr()方法只能返回ascii码,因此在解码中文编的码时就无法正常解码了。网查,讨论,均未解决。留着以后有大佬指点。
最后来个小惊喜
import base64
print(base64.b64encode("AE86".encode("utf-8")))
print(base64.b64decode("QUU4Ng=="))
自己运行吧,不要骂娘就行。你是否感受到python的美丽了,短短一行代码,寥寥几个字母,跟开玩笑一样。我当时惊呆了。好吧,我是确实知道有这个库,自己费费劲自定义一个,深入了解了解编码细则,再看看源码受受打击,一天就过去了哈哈,继续加油吧!!!
附:在线编码解码b64“https://base64.us/”
网友评论