Python允许从给定基数的字符串中轻松创建一个整数

int(str, base). 

我想执行相反的操作:从一个整数创建一个字符串, 例如,我想要一些函数int2base(num, base),这样:

int(int2base(x, b), b) == x

函数名/参数的顺序并不重要。

对于int()将接受的任何以b为底的数字x。

这是一个很容易写的函数:事实上,它比在这个问题中描述它更容易。然而,我觉得我一定是错过了什么。

我知道函数bin, oct, hex,但我不能使用它们的几个原因:

这些函数在旧版本的Python中不可用,我需要与(2.2)兼容 我想要一个通解对于不同的碱都可以用同样的方式表示 我想允许2 8 16以外的底数

相关的

Python优雅的int(string, base)逆函数 在python中使用递归的整数到base-x系统 Python中的Base 62转换 如何在Python中将整数转换为最短的url安全字符串?


当前回答

假设我们想把14转换成2进制。我们反复应用除法算法,直到商为0:

14 = 2 × 7

7 = 2 × 3 + 1

3 = 2 × 1 + 1

1 = 2 × 0 + 1

二进制表示就是从下往上读的余数。这可以通过展开来证明

14 = 2 × 7 = 2 × (2 × 3 + 1) = 2 × (2 × (2 × 1 + 1) + 1) = 2 × (2 × (2 × 0 + 1) + 1) = 2^3 + 2^2 + 2

本代码是上述算法的实现。

def toBaseX(n, X):
strbin = ""
while n != 0:
    strbin += str(n % X)
    n = n // X
return strbin[::-1]

其他回答

如果你需要兼容Python的古老版本,你可以使用gmpy(它包含一个快速的,完全通用的int-to-string转换函数,可以为这样的古老版本构建-你可能需要尝试更老的版本,因为最近的版本还没有针对古老的Python和GMP版本进行测试,只有一些最近的版本),或者,为了速度较慢但更方便,使用Python代码-例如,对于Python 2,最简单的方法是:

import string
digs = string.digits + string.ascii_letters


def int2base(x, base):
    if x < 0:
        sign = -1
    elif x == 0:
        return digs[0]
    else:
        sign = 1

    x *= sign
    digits = []

    while x:
        digits.append(digs[int(x % base)])
        x = int(x / base)

    if sign < 0:
        digits.append('-')

    digits.reverse()

    return ''.join(digits)

对于Python 3, int(x / base)会导致不正确的结果,必须将其更改为x // base:

import string
digs = string.digits + string.ascii_letters


def int2base(x, base):
    if x < 0:
        sign = -1
    elif x == 0:
        return digs[0]
    else:
        sign = 1

    x *= sign
    digits = []

    while x:
        digits.append(digs[x % base])
        x = x // base

    if sign < 0:
        digits.append('-')

    digits.reverse()

    return ''.join(digits)

很棒的答案! 我想我问题的答案是“不”,我并没有错过一些明显的解决方案。 下面是我将使用的函数,它可以浓缩答案中所表达的好想法。

允许调用者提供的字符映射(允许base64编码) 检查负数和零 将复数映射为字符串元组

def int2base(x,b,alphabet='0123456789abcdefghijklmnopqrstuvwxyz'): 'convert an integer to its string representation in a given base' if b<2 or b>len(alphabet): if b==64: # assume base64 rather than raise error alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" else: raise AssertionError("int2base base out of range") if isinstance(x,complex): # return a tuple return ( int2base(x.real,b,alphabet) , int2base(x.imag,b,alphabet) ) if x<=0: if x==0: return alphabet[0] else: return '-' + int2base(-x,b,alphabet) # else x is non-negative real rets='' while x>0: x,idx = divmod(x,b) rets = alphabet[idx] + rets return rets

下面是一个如何将任意基数转换为另一个基数的示例。

from collections import namedtuple

Test = namedtuple("Test", ["n", "from_base", "to_base", "expected"])


def convert(n: int, from_base: int, to_base: int) -> int:
    digits = []
    while n:
        (n, r) = divmod(n, to_base)
        digits.append(r)    
    return sum(from_base ** i * v for i, v in enumerate(digits))


if __name__ == "__main__":
    tests = [
        Test(32, 16, 10, 50),
        Test(32, 20, 10, 62),
        Test(1010, 2, 10, 10),
        Test(8, 10, 8, 10),
        Test(150, 100, 1000, 150),
        Test(1500, 100, 10, 1050000),
    ]

    for test in tests:
        result = convert(*test[:-1])
        assert result == test.expected, f"{test=}, {result=}"
    print("PASSED!!!")

我提出了一个“非优化”的2到9基的解决方案:

  def to_base(N, base=2):
    N_in_base = ''
    while True:
        N_in_base = str(N % base) + N_in_base
        N //= base
        if N == 0:
            break
    return N_in_base

这个解决方案不需要反转最终结果,但实际上并没有优化。请参考以下答案了解原因:https://stackoverflow.com/a/37133870/7896998

def base_conversion(num, base):
    digits = []
    while num > 0:
        num, remainder = divmod(num, base)
        digits.append(remainder)
    return digits[::-1]