Base64 编码核心思想 :
下面我们来考虑以下情况:
根据上图编码方式不难总结 : ASCII 码一字节可以变成Base64编码2字节, 两字节变成3 字节, 反引号是1字节, 8位被断开, 前6位一组, 余下后2 位
末尾的处理 :
代码设计
alphabet = b'ABCDEFGHIJKLMNOPORSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
def base64code(src:str):
ret = bytearray()
if isinstance(src, str):
_src = src.encode()
else:
return
lenth = len(_src) # bytes
offset = 0
for offset in range(0, lenth, 3): # 三位一组
triple = _src[offset:offset+3]
r = 3 - len(triple)
if r: # 不足三位补0
triple += b'\x00'*r
x = int.from_bytes(triple, 'big') # 这里选用的大端模式
for i in range(18, -1, -6): # 二进制情况下向右位移18, 12, 6, 0 四种情况的到我们想要的部分
index = x >> i if i == 18 else x >> i & 0x3F # 与0x3F 只要目标位
ret.append(alphabet[index])
# for j in range(r): # 和下面if语句一样, 置换等号
# ret[-j-1] = 61
if r:
ret[-r:] = b'='*r
return bytes(ret)
show_result = base64code('e')
print(show_result)
show_result = base64code('ef')
print(show_result)
show_result= base64code('efg')
print(show_result)
show_result = base64code('`')
print(show_result)
运行结果
b'ZO=='
b'ZWY='
b'ZWZn'
b'YA=='
Base64 解码码思路:
对应关系如下
YWJj --> abc
24 - 0x18 - 左移18位
22 - 0x16 - 左移12位
9 - 0x9 - 左移6位
35 - 0x23 - 左移0位
011000 010110 001001 100011
01100001 01100010 01100011
0x-------61-------62 ---------63
----------a----------b------------c
代码初步实现
alphbet = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
def base64decode(src: bytes):
ret = bytearray()
lenth = len(src)
if lenth % 4 != 0:
return
step = 4
for offset in range(0, lenth, step):
tmp = 0x00
block = src[offset:offset+step]
for i, c in enumerate(reversed(block)):
index = alphbet.find(c)
if index == -1:
continue
tmp += index << i*6
ret.extend(tmp.to_bytes(3, 'big')) # 大端模式
return bytes(ret.rstrip(b'\x00')) # 把最右边\x00 去掉
txt = "TWFu"
txt = txt.encode()
print(base64decode(txt).decode())
运行结果
Man
改进
from collections import OrderedDict
base_tbl = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
alphbet = OrderedDict(zip(base_tbl, range(64)))
def base64decode(src: bytes):
ret = bytearray()
lenth = len(src)
if lenth % 4 != 0:
return
step = 4 # 每次取4 个
for offset in range(0, lenth, step):
tmp = 0x00
block = src[offset:offset+step]
for i in range(4): # 反查表, 从字符到index
index = alphbet.get(block[-i-1])
if index == -1:
continue
tmp += index << i*6
ret.extend(tmp.to_bytes(3, 'big'))
return bytes(ret.rstrip(b'\x00'))
txt = 'TWFu'
txt = txt.encode()
print(base64decode(txt).decode())
运行结果
Man
基本实现了base64 编解码的全部功能, 当然是用直接引用 base64
模块更简单, 这里只是为了了解base64 编解码的大致原理, 希望对看到这篇文章的朋友有所帮助
import base64
base64.b64encode()
base64.b64decode()