IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> Python手写一个Base64编解码工具 -> 正文阅读

[Python知识库]Python手写一个Base64编解码工具

这里我们只实现标准的base64, 补充位用=填充


编码

下面是base64字符的对照表, 因为base64编码是将6bit表示成8bit,所以在原来的基础上会增长1/3, 另外2^6=64,这也是为什么这个表会有64个索引
A-Za-Z0-9+/一共是64个字符, 编码后如果不够四个字符的倍数需要填充

eg:

I编码到SQ(SQ==带填充)
AM编码到QU0(QU0=带填充)
TJM编码到VEpN(VEpN带填充)
假设我们有一个程序,base64对单词进行编码,连接它们并通过网络发送它们。它对"i"、"am"和"tjm"进行编码,将结果夹在一起而不加填充,并将其传输
传输的数据是SQQU0VEpN, 但是解码之后是I\x04\x14\xd1Q), 就是因为没有填充,错误的解码导致的(Q, 0, 这些字符的数据都丢失了, 所以用了后面的位数,错误的解码导致错误的结果)
请添加图片描述

  1. 首先是对输入类型进行校验,是否是字节流
  2. 由于可能需要补=, 所以分开将不需要补和需要补的部分分开进行转换
  3. 对于不需要填补=字符的,每次取三个字节, 转化成四个字符码值,然后查表得到字符
  4. 对于需要填补=字符的, 可以进行填补3 - 剩余字节个字节
  5. 对于解码类似,将四个字符转换成三个字节
#!usr/bin/python
# -*- coding:utf8 -*-
import string
from typing import Union


class EncodeError(Exception):
    """ python encode error """
    pass


class DecodeError(Exception):
    """ python decode error """
    pass


class Base64(object):
    MIN_LENGTH: int = 4
    MODULO_NUMBER: int = 4
    CHARACTER_TABLE: str = string.ascii_uppercase + string.ascii_lowercase + string.digits + '+/'
    COVERING_CHARACTER: str = '='
    ZERO_CHARACTER = '0'

    @staticmethod
    def encode(s: Union[bytes, bytearray]) -> str:
        if not isinstance(s, (bytes, bytearray)):
            raise TypeError("the input s type is error!")

        """
        <模板字符串>.format(<逗号分隔的参数>)
        模板字符串的格式是{<参数序号>: <格式控制标记>}
        <格式控制标记>包括<填充><对齐><宽度><,><.精度><类型>
        这里是取到8位bit,不足补0
        """
        base64_bytes = ['{:0>8}'.format(bin(character).replace('0b', '')) for character in s]

        result = list()
        # 这里需要转换的次数,3个bytes一转换
        translate_count = len(base64_bytes) // 3
        # 剩余1字节可构造2个字符, 需要加2个==, 剩余2个字节可以构造3个字符, 补充1个=
        left_count = len(base64_bytes) % 3
        covering_count = 3 - left_count
        translate_part = base64_bytes[0: 3 * translate_count]

        while translate_part:
            origin_unit = ''.join(translate_part[0:3])
            # 要将3个字节取6bit转换4次, 0->5, 6->11, 12->18
            translate_part_unit = [int(origin_unit[x: x + 6], 2) for x in range(0, 19, 6)]
            result.extend([Base64.CHARACTER_TABLE[i] for i in translate_part_unit])
            translate_part = translate_part[3:]

        if left_count:
            covering_unit = ''.join(base64_bytes[3 * translate_count:]) + covering_count * '0' * 8
            translate_count = left_count + 1
            left_part_unit = [int(covering_unit[x: x + 6], 2) for x in range(0, 19, 6)][:translate_count]
            result.extend([Base64.CHARACTER_TABLE[i] for i in left_part_unit])
            result.append(covering_count * Base64.COVERING_CHARACTER)

        return ''.join(result)

    @staticmethod
    def __valid_base64_str(s: str) -> bool:
        if len(s) < Base64.MIN_LENGTH and len(s) % Base64.MODULO_NUMBER != 0:
            return False

        for index, character in enumerate(s):
            if character not in (Base64.CHARACTER_TABLE + Base64.COVERING_CHARACTER):
                return False

            if character in Base64.COVERING_CHARACTER:
                if len(s[index:]) > 2:
                    return False

            if index == 0:
                continue

            if s[index - 1] in Base64.COVERING_CHARACTER and character not in Base64.COVERING_CHARACTER:
                return False

        return True

    @staticmethod
    def decode(s: str):
        if not Base64.__valid_base64_str(s):
            raise DecodeError("input s is invalid!")

        base64_bytes = ['{:0>6}'.format(bin(Base64.CHARACTER_TABLE.index(character)).replace('0b', ''))
                        for character in s if character != Base64.COVERING_CHARACTER]

        result = bytearray()
        translate_count = len(base64_bytes) // 4
        # 剩余1字节可构造2个字符, 需要加2个==, 剩余2个字节可以构造3个字符, 补充1个=
        covering_count = len(base64_bytes) % 4
        left_count = covering_count - 1
        translate_part = base64_bytes[0: 4 * translate_count]

        while translate_part:
            origin_unit = ''.join(translate_part[0:4])
            # 要将3个字节取6bit转换4次, 0->5, 6->11, 12->18
            translate_part_unit = [int(origin_unit[x: x + 8], 2) for x in range(0, 17, 8)]
            result.extend(translate_part_unit)
            translate_part = translate_part[4:]

        if covering_count:
            covering_unit = ''.join(base64_bytes[translate_count * 4:])
            left_part_unit = [int(covering_unit[x * 8: x * 8 + 8], 2) for x in range(left_count)]
            result.extend(left_part_unit)

        return result


if __name__ == '__main__':
    print(Base64.encode(b'i\xb7\x1d\xfb\xef\xff'))
    print(Base64.decode("abcd++//"))
    assert Base64.encode(b'i\xb7\x1d\xfb\xef\xff') == "abcd++//"
    assert Base64.decode("abcd++//") == b'i\xb7\x1d\xfb\xef\xff'
  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2021-12-05 12:00:09  更:2021-12-05 12:00:52 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/16 3:39:55-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码