Base64编码与解码 ——Python实现

1. 引言

记录学习base64编码与解码的思考以及通过Python实现。

2. Base64简介

这里请参考文章:一文彻底看懂Base64原理
声明: 本文的图片均来自上述文章。
我的理解就是,将待编码字符集合与二进制{0, 1}之间相互的等价转换情况。
注意:base64是一种可以算是公开的加密方法 ,只能加密保护某些数据。

3. 预习知识

本小节主要介绍字节、二进制、ASCII码等知识,如果很熟悉可以跳过。

3.1 字节

数据存储是以“字节”(Byte)为单位,数据传输大多是以“位”(bit,又名“比特”)为单位,一个位就代表一个0或1(即二进制),每8个位(bit,简写为b)组成一个字节(Byte,简写为B),是最小一级的信息单位。
8bit(位)=1Byte(字节)

3.2 二进制 与字节

因为计算机通信和存储的时候都bai是以010101这样的二进制数据为基础du的,这儿的一个0和1占的地方就叫bit(位),即一个二进制位。

3.3 ASCII码

ASCII码中:一个英文字母(不bai分大小写)占一个字节的空间,du一个中文汉字占两个字节的空间。
ASCII码对照表:ASCII码对照表

3. Base64编码

这里着重讲我自己的理解思路 ,原理还是参考文章开头提到的链接。
本文用的字符集

base64_charset = string.ascii_uppercase + string.ascii_lowercase + string.digits + '+/'

编码过程如下:

3.1 个人理解

  1. 将三个字节(字符)作为一组,也就转换成3✖️8 = 24 bit,如果不足三个字节(24bit),则补0。
  2. 再将上边的24bit转换成四组,即每组6bit。
  3. 将第二步得到的四组数据高位补0,实现完整的4个字节,即4✖️8 = 32 bit,每个字节表示base64的字符集索引。
  4. 将每个扩展后的新的8bit用作表示整数的索引,对应字符集的一个字符,这就是编码后的值。
  5. 最后处理在步骤1中不足3字节的情况 ,缺一个字节索引,即为0时候,补一个=,缺两个就补两个=。
    注意: 高位补0,可以让原数不变,是高位。

3.2 代码实现

str的相关用法

def encode(origin_str):

    # 将字符串转化为字节
    origin_bytes = str(origin_str).encode()

    # 将每一位bytes转换为二进制字符串,高位补0,这里涉及str的format用法
    # 可以百度,也可以参考https://blog.csdn.net/qq_42009978/article/details/107739538
    str_bytes = ['{:0>8}'.format(str(bin(b)).replace('0b', '')) for b in origin_bytes]

    resp = ''
    # 3个一组,整除3,看总共有多少组
    group_nums = len(str_bytes) // 3
    # 看余数剩几个字符
    remain_str_nums = len(str_bytes) % 3

    integral_part = str_bytes[0: 3 * group_nums]
    while integral_part:
        # 取三个字节,以每6比特,转换为4个整数
        tmp_bytes = ''.join(integral_part[0:3])
        tmp_bytes = [int(tmp_bytes[x: x + 6], 2) for x in [0, 6, 12,  18]]
        # 取对应base64字符
        resp += ''.join([base64_charset[i] for i in tmp_bytes])
        integral_part = integral_part[3:]

    if remain_str_nums:
        # 补齐三个字节,每个字节补充 00000000
        remain_part = ''.join(str_bytes[3 * group_nums:]) + (3 - remain_str_nums) * '0' * 8
        tmp_bytes = [int(remain_part[x: x + 6], 2) for x in [0, 6, 12, 18]][: remain_str_nums + 1]  # 这里是对数组进行截取,为了防止产生不必要的数据
        # 剩余1字节可构造2个base64字符,补充==;剩余2字节可构造3个base64字符,补充=
        resp += ''.join([base64_charset[i] for i in tmp_bytes]) + (3 - remain_str_nums) * '='

    return resp

4. Base64解码

解码的过程实际上是编码的一个逆过程,理解了编码,解码也就对应二声了。

4.1 个人理解

  1. 判定给出的字符串是不是一个合法的经过Base64编码的字符串。
  2. 对每一个base64字符取下标索引,并转换为6位二进制字符串。
  3. 取4个6位base64字符,作为3个字节。
  4. 最后将不足四个的base64字符,进行其他处理。

4.2 代码实现

# 判定是否合法
def isValidBase64_str(base64_str):
    if len(base64_str) % 4:
        return False
    for b in base64_str:
        if b not in base64_charset and b is not '=':
            return False
    return True

def decode(base64_str, isFormat = '0'):

    if not isValidBase64_str(base64_str):
        return bytearray

    # 对每一个base64字符取下标索引,并转换为6位二进制字符串
    base64_bytes = ['{:0>6}'.format(str(bin(base64_charset.index(s))).replace('0b', '')) for s in base64_str if
                    s != '=']

    resp = bytearray()

    group_nums = len(base64_bytes) // 4

    remain_str_nums = len(base64_bytes) % 4

    integral_part = base64_bytes[0: 4 * group_nums]
    while integral_part:
        # 取4个6位base64字符,作为3个字节
        tmp_str = ''.join(integral_part[0: 4])
        tmp_str = [int(tmp_str[x: x + 8], 2) for x in [0, 8, 16]]

        for i in tmp_str:
            resp.append(i)

        integral_part = integral_part[4: ]

    if remain_str_nums:
        remain_part = ''.join(base64_bytes[group_nums * 4:])
        tmp_str = [int(remain_part[i * 8: (i + 1) * 8], 2) for i in range(remain_str_nums - 1)]

        for i in tmp_str:
            resp.append(i)

    output_str = resp.decode()

    if isFormat == '1':
        # 相应的处理
        print(isFormat)

    return output_str
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值