Python-57:Base32编码和解码问题
问题描述
你需要实现一个 Base32 的编码和解码函数。
相比于 Base32,你可能更熟悉 Base64,Base64 是非常常见的用字符串形式表示二进制数据的方式,在邮件附件、Web 中的图片中都有广泛的应用。
Base32 是 Base64 的变种,与 Base64 不同的地方在于 Base64 以 6 bit 为一组作为索引,而 Base32 以 5 bit 为一组作为索引,每一组用一个 ASCII 字符表示。Base 64 总共需要 64 个字符表示,而 Base32 则只需要 32 个字符表示。
Base32 的编码流程如下:
- 对二进制数据进行预处理:如果二进制数据的 bit 数目不是 5 的倍数的话,在末尾补 0 直至为 5 的倍数。
- 以 5 bit 为一组进行分组。
- 将每一组的 5 bit 二进制转换为索引(0 - 31)。
- 在索引 - 字符转换表中查询索引对应的字符。
- 根据原始二进制数据的 bit 数目除以 40 后的余数,确定末尾需要补
+
的数目。 - 如果原始二进制数据 bit 数目除以 40 后的余数是 0 的话,不需要补
+
。 - 如果余数是 8,补 6 个
+
。 - 如果余数是 16,补 4 个
+
。 - 如果余数是 24,补 3 个
+
。 - 如果余数是 32,补 1 个
+
。
Base32 的索引 - 字符转换表如下:
索引:0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
字符:9 8 7 6 5 4 3 2 1 0 m n b v c x z a s d f g h j k l p o i u y t
你需要对字符串rawStr
进行编码,并对encodedStr
进行解码。
代码
STRING_LIST = '9876543210mnbvcxzasdfghjklpoiuyt'
CHAR_MAP = {char: i for i, char in enumerate(STRING_LIST)}
PAD = '+'
PAD_COUNT_MAP = {40: 0, 8: 6, 16: 4, 24: 3, 32: 1}
def encode(str_input: str) -> str:
binary_array = []
for char in str_input:
binary = bin(ord(char))[2:]
binary_array.append(binary.zfill((len(binary) + 7) // 8 * 8))
binary_string = ''.join(binary_array)
groups = []
fragments = []
if len(binary_string) <= 40:
groups.append(binary_string)
else:
segments = -(-len(binary_string) // 40) # Ceiling division
for i in range(segments):
groups.append(binary_string[40 * i:40 * (i + 1)])
pad_count = PAD_COUNT_MAP[len(groups[-1])]
groups[-1] = groups[-1].ljust(40, '0')
for index, s in enumerate(groups):
group = []
border = 8 - pad_count if index == len(groups) - 1 else 8
for i in range(border):
sequence = s[5 * i:5 * (i + 1)]
idx = int(sequence, 2)
group.append(STRING_LIST[idx])
fragments.append(''.join(group))
fragments.append(PAD * pad_count)
return ''.join(fragments)
def decode(data: str) -> str:
char_array = list(data)
unit8_array = []
carry = ''
for char in char_array:
if char == PAD:
carry = ''
continue
index = CHAR_MAP[char]
index_in_binary = carry + bin(index)[2:].zfill(5)
if len(index_in_binary) <= 8:
carry = index_in_binary
else:
unit8_array.append(int(index_in_binary[:8], 2))
carry = index_in_binary[8:]
return ''.join(chr(byte) for byte in unit8_array)
def solution(rawStr: str, encodedStr: str) -> str:
return f"{encode(rawStr)}:{decode(encodedStr)}"
if __name__ == "__main__":
# You can add more test cases here
print(solution("foo", "b0zj5+++") == "bljhy+++:bar" )
print(solution("The encoding process", "bljhy+++b0zj5+++") == "maf3m164vlahyl60vlds9i6svuahmiod:foobar" )
print(solution("Base32 encoding and decoding", "bvchz+++v4j21+++cals9+++") == "10zj3l0d31z3mod6vus3sod258zhil89bash3oo5v4j3c+++:c]hintts " )