# 将每⼀位bytes转换为二进制字符串,用bin转换后是0b开头的,所以把0b替换了,首位补0补齐8位 base64_bytes = ['{:0>8}'.format(str(bin(b)).replace('0b', '')) for b in origin_bytes] resp = '' nums = len(base64_bytes) // 3 remain = len(base64_bytes) % 3 integral_part = base64_bytes[0:3 * nums] while integral_part: # 取三个字节,以每6⽐特,转换为4个整数 tmp_unit = ''.join(integral_part[0:3]) tmp_unit = [int(tmp_unit[x: x + 6], 2) for x in [0, 6, 12, 18]] # 取对应base64字符 resp += ''.join([base64_charset[i] for i in tmp_unit]) integral_part = integral_part[3:] if remain: # 补⻬三个字节,每个字节补充 0000 0000 remain_part = ''.join(base64_bytes[3 * nums:]) + (3 - remain) * '0' * 8 # 取三个字节,以每6⽐特,转换为4个整数 # 剩余1字节可构造2个base64字符,补充==;剩余2字节可构造3个base64字符,补充= tmp_unit = [int(remain_part[x: x + 6], 2) for x in [0, 6, 12, 18]][:remain + 1] resp += ''.join([base64_charset[i] for i in tmp_unit]) + (3 - remain) * '=' return resp
defdecode(base64_str): ifnot valid_base64_str(base64_str): returnbytearray() base64_bytes = ['{:0>6}'.format(str(bin(base64_charset.index(s))).replace('0b','')) for s in base64_str if s != '='] resp = bytearray() nums = len(base64_bytes) // 4 remain = len(base64_bytes) % 4 integral_part = base64_bytes[0:4 * nums] while integral_part: # 取4个6位base64字符,作为3个字节 tmp_unit = ''.join(integral_part[0:4]) tmp_unit = [int(tmp_unit[x: x + 8], 2) for x in [0, 8, 16]] for i in tmp_unit: resp.append(i) integral_part = integral_part[4:] if remain: remain_part = ''.join(base64_bytes[nums * 4:]) tmp_unit = [int(remain_part[i * 8:(i + 1) * 8], 2) for i inrange(remain - 1)] for i in tmp_unit: resp.append(i) return resp
defvalid_base64_str(b_str): iflen(b_str) % 4: returnFalse for m in b_str: if m != "="and m notin base64_charset: returnFalse returnTrue
与Base64一样,Base58编码的作用也是将非可视字符可视化(ASCII化)。但不同的是Base58编码去掉了几个看起来会产生歧义的字符,如 0 (零), O (大写字母O), I (大写的字母i) and l (小写的字母L) ,和几个影响双击选择的字符,如/, +。结果字符集正好58个字符(包括9个数字,24个大写字母,25个小写字母)。而且因为58不是2的整次幂,所以没有使用类似Base64编码中使用直接截取3个字符转4个字符($38=46$ , 2的6次方刚好64)的方法进行转换,而是采用我们数学上经常使用的进制转换方法——辗转相除法(本质上,Base64编码是64进制,Base58是58进制)。看下Base58的编码表:
defbase36encode(number, alphabet='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'): """Converts an integer to a base36 string.""" ifnotisinstance(number, (int, int)): raise TypeError('number must be an integer')
base36 = '' sign = ''
if number < 0: sign = '-' number = -number
# 如果输入的整数大于等于0小于36,直接返回索引表中的值 if0 <= number < len(alphabet): return sign + alphabet[number] # 商,余数 = divmod(被除数,除数) while number != 0: number, i = divmod(number, len(alphabet)) base36 = alphabet[i] + base36
defbase62encode(num, alphabet=BASE62): """Encode a positive number into Base X and return the string. Arguments: - `num`: The number to encode - `alphabet`: The alphabet to use for encoding """ if num == 0: return alphabet[0] arr = [] arr_append = arr.append # Extract bound-method for faster access. _divmod = divmod# Access to locals is faster. base = len(alphabet) while num: num, rem = _divmod(num, base) arr_append(alphabet[rem]) arr.reverse() return''.join(arr)
defbase62decode(string, alphabet=BASE62): """Decode a Base X encoded string into the number Arguments: - `string`: The encoded string - `alphabet`: The alphabet to use for decoding """ base = len(alphabet) strlen = len(string) num = 0
idx = 0 for char in string: power = (strlen - (idx + 1)) num += alphabet.index(char) * (base ** power) idx += 1