努力将数字转换为 Python 中的 base 64,没有字符串

Struggling to convert a number to base 64 in Python without strings

所以我正在尝试对我发现的这个很酷的项目进行编程(在 Python 3 中没有字符串)。

Return 36 位数字 n 的 6 个字符的字符串表示形式为倒序的 base-64 数字,其中 64 位数字的顺序为:

0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-+

例如,

encode(0) → '000000'
encode(9876543210) → 'gR1iC9'
encode(68719476735) → '++++++'

我目前拥有的是:

def encode(n):
  SYM = {'0': 0,
         '1': 1,
         '2': 2,
         '3': 3,
         '4': 4,
         '5': 5,
         '6': 6,
         '7': 7,
         '8': 8,
         '9': 9,
         'A': 10,
         'B': 11,
         'C': 12,
         'D': 13,
         'E': 14,
         'F': 15,
         'G': 16,
         'H': 17,
         'I': 18,
         'J': 19,
         'K': 20,
         'L': 21,
         'M': 22,
         'N': 23,
         'O': 24,
         'P': 25,
         'Q': 26,
         'R': 27,
         'S': 28,
         'T': 29,
         'U': 30,
         'V': 31,
         'W': 32,
         'X': 33,
         'Y': 34,
         'Z': 35,
         'a': 36,
         'b': 37,
         'c': 38,
         'd': 39,
         'e': 40,
         'f': 41,
         'g': 42,
         'h': 43,
         'i': 44,
         'j': 45,
         'k': 46,
         'l': 47,
         'm': 48,
         'n': 49,
         'o': 50,
         'p': 51,
         'q': 52,
         'r': 53,
         's': 54,
         't': 55,
         'u': 56,
         'v': 57,
         'w': 58,
         'x': 59,
         'y': 60,
         'z': 61,
         '-': 62,
         '+': 63,}

但现在我不确定下一步该做什么。我不想使用字符串和连接等,我想使用 modulus 和标准数论 + for/while/else 方法来做到这一点。

我的想法是定义

r1 = n % 63
r2 = r1 % 63
r3 = r2 % 63
r4 = r3 % 63
r5 = r4 % 63
r6 = r5 % 63

但我不确定接下来该做什么。

例如,我应该如何将 n 转换为 base 64?最后,为了在找到新表示后反转数字,我想我将 mod 10 的每个幂来隔离每个单独的数字,然后以相反的顺序连接它们。但是,我不确定如何在 Python 中对此进行编程,因为我对这种语言还比较陌生。感谢所有帮助,谢谢。

这里有一些代码可以满足您的需求。 get_digit函数使用一堆if... elif测试将0 <= d < 64中的整数d转换成其对应的字符数,然后使用标准的chr函数将该数字转换为实际字符。 encode 函数执行实际的余数计算,调用 get_digit 进行字符转换,并将结果保存到 out 列表中。我们在该列表后附加 '0' 个字符,使其长度为 6。

def get_digit(d):
    ''' Convert a base 64 digit to the desired character '''
    if 0 <= d <= 9:
        # 0 - 9
        c = 48 + d
    elif 10 <= d <= 35:
        # A - Z
        c = 55 + d
    elif 36 <= d <= 61:
        # a - z
        c = 61 + d
    elif d == 62:
        # -
        c = 45
    elif d == 63:
        # +
        c = 43
    else:
        # We should never get here
        raise ValueError('Invalid digit for base 64: ' + str(d)) 
    return chr(c)

# Test `digit`
print(''.join([get_digit(d) for d in range(64)]))

def encode(n):
    ''' Convert integer n to base 64 '''
    out = []
    while n:
        n, r = n // 64, n % 64
        out.append(get_digit(r))
    while len(out) < 6:
        out.append('0')
    return ''.join(out)

# Test `encode`
for i in (0, 9876543210, 68719476735):
    print(i, encode(i))

输出

0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-+
0 000000
9876543210 gR1iC9
68719476735 ++++++

由于我们使用的是 2 的幂的基数,因此可以替代

n, r = n // 64, n % 64

是使用位运算

n, r = n >> 64, n & 63

稍微快一点,但我想这在这里没有太大区别,而且前面的代码更具可读性。 OTOH,了解按位版本产生正确结果的原因可能很有用。