python自定义解决base64编码

作者: 爱吃西红柿嘛 | 来源:发表于2020-03-21 17:00 被阅读0次

    前瞻知识

    先来了解一下,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编码,令人感到十分兴奋的是,并无复杂算法,直接给出索引表,每一位字节转换为十进制之后,对号入座即可

    Base64编码索引表

    热菜

    好了,话不多说,该上热乎乎的代码了。

    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/

    相关文章

      网友评论

        本文标题:python自定义解决base64编码

        本文链接:https://www.haomeiwen.com/subject/azzyyhtx.html