代码之家  ›  专栏  ›  技术社区  ›  Mark Borgerding

如何将任意基的整数转换为字符串?

  •  174
  • Mark Borgerding  · 技术社区  · 15 年前

    python允许从给定基的字符串通过

    int(str, base). 
    

    我想做相反的: 从整数创建字符串 ,请 也就是说,我想要一些功能 int2base(num, base) ,例如:

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

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

    任何号码 x 基础 b 那个 int() 将接受。

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

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

    • 这些函数在旧版本的python上不可用,我需要与之兼容(2.2)

    • 我想要一个通用的解决方案,可以用同样的方法来处理不同的碱基

    • 我想允许2,8,16以外的基地

    相关的

    23 回复  |  直到 6 年前
        1
  •  84
  •   Devin    7 年前

    如果需要与Python的古代版本兼容,可以使用 gmpy (它包含了一个快速的、完全通用的int到string转换函数,并且可以为这样的古老版本而构建——您可能需要尝试较旧的版本,因为最近的版本还没有经过古老的python和gmp版本的测试,只是有点新的版本),或者为了速度更低但更方便,使用python代码——例如,最简单的Y:

    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)
    
        2
  •  85
  •   lifolofi jellyfishtree    8 年前
    def baseN(num,b,numerals="0123456789abcdefghijklmnopqrstuvwxyz"):
        return ((num == 0) and numerals[0]) or (baseN(num // b, b, numerals).lstrip(numerals[0]) + numerals[num % b])
    

    裁判: http://code.activestate.com/recipes/65212/

    请注意,这可能导致

    RuntimeError: maximum recursion depth exceeded in cmp
    

    对于非常大的整数。

        3
  •  80
  •   user2357112    6 年前

    令人惊讶的是,人们只给出了转换成小碱基(比英语字母表的长度小)的解决方案。没有试图给出一个从2到无穷大的任意基的解。

    所以这里有一个非常简单的解决方案:

    def numberToBase(n, b):
        if n == 0:
            return [0]
        digits = []
        while n:
            digits.append(int(n % b))
            n //= b
        return digits[::-1]
    

    所以如果你需要把一些超大的数字转换成基数 577 ,

    numberToBase(67854 ** 15 - 102, 577) ,将为您提供正确的解决方案: [4, 473, 131, 96, 431, 285, 524, 486, 28, 23, 16, 82, 292, 538, 149, 25, 41, 483, 100, 517, 131, 28, 0, 435, 197, 264, 455] ,

    以后可以转换成任何基础

        4
  •  67
  •   Rost    14 年前
    "{0:b}".format(100) # bin: 1100100
    "{0:x}".format(100) # hex: 64
    "{0:o}".format(100) # oct: 144
    
        5
  •  20
  •   ivan_pozdeev RenanSS    10 年前

    答案很好! 我想我的问题的答案是“不”,我没有遗漏一些明显的解决办法。 下面是我将使用的功能,它浓缩了答案中表达的好想法。

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

    < PRE> >代码> def int2base(x,b,alphabet='0123456789abcdefghijklmnopqrstuvwxyz'): '将整数转换为给定基中的字符串表示形式' 如果b<2或b>len(字母表): 如果b==64:假设base64而不是引发错误 alphabet=“abcdefghijklmnopqrstuvwxyzabcefghijklmnopqrstuvwxyz0123456789+/” 其他: 引发断言错误(“Int2Base超出范围”) 如果isInstance(x,complex):返回元组 返回(int2base(x.real,b,alphabet),int2base(x.imag,b,alphabet)) 如果x<=0: 如果x=0: 返回字母[0] 其他: 返回'-'+Int2Base(-x,b,字母表) #否则x是非负实数 里茨= 而x & gt;0: x,idx=divmod(x,b) rets=字母[idx]+rets 退货税

    . >.

    瓮元组
    返回(int2base(x.real,b,alphabet),int2base(x.imag,b,alphabet))
    如果x<=0:
    如果x=0:
    返回字母[0]
    其他:
    返回'-'+Int2Base(-x,b,字母表)
    #否则x是非负实数
    里茨=
    而x & gt;0:
    x,idx=divmod(x,b)
    rets=字母[idx]+rets
    退货税
    
    

        6
  •  14
  •   Mike Graham    15 年前

    python没有用于在任意基中打印整数的内置函数。如果你想的话,你必须自己写。

        7
  •  13
  •   iBug    7 年前

    你可以使用 baseconv.py 从我的项目: https://github.com/semente/python-baseconv

    样品使用情况:

    >>> from baseconv import BaseConverter
    >>> base20 = BaseConverter('0123456789abcdefghij')
    >>> base20.encode(1234)
    '31e'
    >>> base20.decode('31e')
    '1234'
    >>> base20.encode(-1234)
    '-31e'
    >>> base20.decode('-31e')
    '-1234'
    >>> base11 = BaseConverter('0123456789-', sign='$')
    >>> base11.encode('$1234')
    '$-22'
    >>> base11.decode('$-22')
    '$1234'
    

    例如,有一些Bultin转换器 baseconv.base2 , baseconv.base16 baseconv.base64 .

        8
  •  4
  •   John La Rooy    15 年前

    http://code.activestate.com/recipes/65212/

    def base10toN(num,n):
        """Change a  to a base-n number.
        Up to base-36 is supported without special notation."""
        num_rep={10:'a',
             11:'b',
             12:'c',
             13:'d',
             14:'e',
             15:'f',
             16:'g',
             17:'h',
             18:'i',
             19:'j',
             20:'k',
             21:'l',
             22:'m',
             23:'n',
             24:'o',
             25:'p',
             26:'q',
             27:'r',
             28:'s',
             29:'t',
             30:'u',
             31:'v',
             32:'w',
             33:'x',
             34:'y',
             35:'z'}
        new_num_string=''
        current=num
        while current!=0:
            remainder=current%n
            if 36>remainder>9:
                remainder_string=num_rep[remainder]
            elif remainder>=36:
                remainder_string='('+str(remainder)+')'
            else:
                remainder_string=str(remainder)
            new_num_string=remainder_string+new_num_string
            current=current/n
        return new_num_string
    

    这是同一个链接的另一个链接

    def baseconvert(n, base):
        """convert positive decimal integer n to equivalent in another base (2-36)"""
    
        digits = "0123456789abcdefghijklmnopqrstuvwxyz"
    
        try:
            n = int(n)
            base = int(base)
        except:
            return ""
    
        if n < 0 or base < 2 or base > 36:
            return ""
    
        s = ""
        while 1:
            r = n % base
            s = digits[r] + s
            n = n / base
            if n == 0:
                break
    
        return s
    
        9
  •  3
  •   Belldandu    8 年前

    我做了一个PIP包。

    我建议你用我的基地。 https://github.com/kamijoutouma/bases.py 灵感来源于bases.js

    from bases import Bases
    bases = Bases()
    
    bases.toBase16(200)                // => 'c8'
    bases.toBase(200, 16)              // => 'c8'
    bases.toBase62(99999)              // => 'q0T'
    bases.toBase(200, 62)              // => 'q0T'
    bases.toAlphabet(300, 'aAbBcC')    // => 'Abba'
    
    bases.fromBase16('c8')               // => 200
    bases.fromBase('c8', 16)             // => 200
    bases.fromBase62('q0T')              // => 99999
    bases.fromBase('q0T', 62)            // => 99999
    bases.fromAlphabet('Abba', 'aAbBcC') // => 300
    

    参照 https://github.com/kamijoutouma/bases.py#known-basesalphabets 什么样的基础是有用的

    编辑: 匹普链接 https://pypi.python.org/pypi/bases.py/0.2.2

        10
  •  3
  •   Xavier Guihot    6 年前

    递归的

    我愿意 简化 这个 most voted answer 收件人:

    BS="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    def to_base(n, b): 
        return "0" if not n else to_base(n//b, b).lstrip("0") + BS[n%b]
    

    同样的建议 RuntimeError: maximum recursion depth exceeded in cmp 在非常大的整数和负数上。(你可以使用 sys.setrecursionlimit(new_limit) )

    迭代的

    避免递归问题 :

    BS="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    def to_base(s, b):
        res = ""
        while s:
            res+=BS[s%b]
            s//= b
        return res[::-1] or "0"
    
        11
  •  3
  •   user2683246    6 年前
    def base(decimal ,base) :
        list = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        other_base = ""
        while decimal != 0 :
            other_base = list[decimal % base] + other_base
            decimal    = decimal / base
        if other_base == "":
            other_base = "0"
        return other_base
    
    print base(31 ,16)
    

    输出:

    “一层”

        12
  •  1
  •   SilentGhost    15 年前
    >>> import string
    >>> def int2base(integer, base):
            if not integer: return '0'
            sign = 1 if integer > 0 else -1
            alphanum = string.digits + string.ascii_lowercase
            nums = alphanum[:base]
            res = ''
            integer *= sign
            while integer:
                    integer, mod = divmod(integer, base)
                    res += nums[mod]
            return ('' if sign == 1 else '-') + res[::-1]
    
    
    >>> int2base(-15645, 23)
    '-16d5'
    >>> int2base(213, 21)
    'a3'
    
        13
  •  1
  •   Mr. Polywhirl    10 年前

    对感兴趣的人的递归解决方案。当然,这对负二进制值不起作用。您需要实现二的补码。

    def generateBase36Alphabet():
        return ''.join([str(i) for i in range(10)]+[chr(i+65) for i in range(26)])
    
    def generateAlphabet(base):
        return generateBase36Alphabet()[:base]
    
    def intToStr(n, base, alphabet):
        def toStr(n, base, alphabet):
            return alphabet[n] if n < base else toStr(n//base,base,alphabet) + alphabet[n%base]
        return ('-' if n < 0 else '') + toStr(abs(n), base, alphabet)
    
    print('{} -> {}'.format(-31, intToStr(-31, 16, generateAlphabet(16)))) # -31 -> -1F
    
        14
  •  1
  •   Shu ba    9 年前
    def int2base(a, base, numerals="0123456789abcdefghijklmnopqrstuvwxyz"):
        baseit = lambda a=a, b=base: (not a) and numerals[0]  or baseit(a-a%b,b*base)+numerals[a%b%(base-1) or (a%b) and (base-1)]
        return baseit()
    

    解释

    在任何基数中,每个数字都等于 a1+a2*base**2+a3*base**3... “任务”是找到所有的A。

    对于每一个 N=1,2,3... 代码正在隔离 aN*base**N 由B为 b=base**(N+1) 把所有a的大于n的切片,把所有a的序列都小于n的切片,每次函数被当前调用时都减少一个。 A*BASE**N .

    基%(base-1)==1,因此,基**p%(base-1)==1,因此q*基^ p%(base-1)==q,当q=base-1返回0时,只有一个例外。 为了解决这个问题,如果返回0,func将检查begining中的0。


    优势

    在这个样本中,只有一个乘法(而不是除法)和一些相对花费少量时间的模。

        15
  •  0
  •   nameisnotphil    9 年前
    def dec_to_radix(input, to_radix=2, power=None):
        if not isinstance(input, int):
            raise TypeError('Not an integer!')
        elif power is None:
            power = 1
    
        if input == 0:
            return 0
        else:
            remainder = input % to_radix**power
            digit = str(int(remainder/to_radix**(power-1)))
            return int(str(dec_to_radix(input-remainder, to_radix, power+1)) + digit)
    
    def radix_to_dec(input, from_radix):
        if not isinstance(input, int):
            raise TypeError('Not an integer!')
        return sum(int(digit)*(from_radix**power) for power, digit in enumerate(str(input)[::-1]))
    
    def radix_to_radix(input, from_radix=10, to_radix=2, power=None):
        dec = radix_to_dec(input, from_radix)
        return dec_to_radix(dec, to_radix, power)
    
        16
  •  0
  •   Ariel    9 年前

    另一个简短的(并且更容易理解IMO):

    def int_to_str(n, b, symbols='0123456789abcdefghijklmnopqrstuvwxyz'):
        return (int_to_str(n/b, b, symbols) if n >= b else "") + symbols[n%b]
    

    以及适当的例外处理:

    def int_to_str(n, b, symbols='0123456789abcdefghijklmnopqrstuvwxyz'):
        try:
            return (int_to_str(n/b, b) if n >= b else "") + symbols[n%b]
        except IndexError:
            raise ValueError(
                "The symbols provided are not enough to represent this number in "
                "this base")
    
        17
  •  0
  •   Stanislav    9 年前

    另一种解决方案是使用碱2到碱10,需要对更高的碱进行修改:

    def n2b(n, b):
        if n == 0:
            return 0
        d = []
        while n:
            d.append(int(n % b))
            n /= b
        return ''.join(map(str,d[::-1]))
    

    例子:

    n2b(10,2) => '10100'
    int(n2b(10,2),2) => 10
    
        18
  •  0
  •   Antoine Pinsard    8 年前

    这里是一个递归版本,处理有符号整数和自定义数字。

    import string
    
    def base_convert(x, base, digits=None):
        """Convert integer `x` from base 10 to base `base` using `digits` characters as digits.
        If `digits` is omitted, it will use decimal digits + lowercase letters + uppercase letters.
        """
        digits = digits or (string.digits + string.ascii_letters)
        assert 2 <= base <= len(digits), "Unsupported base: {}".format(base)
        if x == 0:
            return digits[0]
        sign = '-' if x < 0 else ''
        x = abs(x)
        first_digits = base_convert(x // base, base, digits).lstrip(digits[0])
        return sign + first_digits + digits[x % base]
    
        19
  •  0
  •   jay a gjivanya    8 年前
    def baseConverter(x, b):
        s = ""
        d = string.printable.upper()
        while x > 0:
            s += d[x%b]
            x = x / b
        return s[::-1]
    
        20
  •  0
  •   Casey Howard    6 年前
    num = input("number")
    power = 0
    num = int(num)
    while num > 10:
        num = num / 10
        power += 1
    
    print(str(round(num, 2)) + "^" + str(power))
    
        21
  •  -1
  •   colski    8 年前

    字符串不是表示数字的唯一选择:您可以使用整数列表来表示每个数字的顺序。这些可以很容易地转换为字符串。

    所有答案都不会拒绝基本答案<2;,大多数答案的运行速度会非常慢,或者由于堆栈溢出而崩溃。 非常大 数字(如56789**43210)。要避免此类故障,请像这样快速减少:

    def n_to_base(n, b):
        if b < 2: raise # invalid base
        if abs(n) < b: return [n]
        ret = [y for d in n_to_base(n, b*b) for y in divmod(d, b)]
        return ret[1:] if ret[0] == 0 else ret # remove leading zeros
    
    def base_to_n(v, b):
        h = len(v) // 2
        if h == 0: return v[0]
        return base_to_n(v[:-h], b) * (b**h) + base_to_n(v[-h:], b)
    
    assert ''.join(['0123456789'[x] for x in n_to_base(56789**43210,10)])==str(56789**43210)
    

    Speedwise n_to_base 可与 str 对于较大的数字(在我的机器上大约是0.3秒),但如果与 hex 你可能会感到惊讶(我的机器大约有0.3毫秒,或者快1000倍)。原因是大整数以256(字节)为基数存储在内存中。每个字节可以简单地转换为两个字符的十六进制字符串。这种对齐只发生在2次幂的基上,这就是为什么2、8和16(以及base64、ascii、utf16和utf32)有特殊情况的原因。

    考虑十进制字符串的最后一位。它如何与构成整数的字节序列相关?让我们标记字节 s[i] 具有 s[0] 最不重要的(小尾数)。那么最后一个数字是 sum([s[i]*(256**i) % 10 for i in range(n)]) . 好吧,正好256**i以6结尾,表示i>0(6*6=36),所以最后一个数字是 (s[0]*5 + sum(s)*6)%10 . 从这里,您可以看到最后一个数字取决于所有字节的总和。这种非局部属性使得转换为十进制更加困难。

        22
  •  -1
  •   cmdLP    8 年前

    我在这里没有看到任何浮筒转换器。我总是错过了三位数的分组。

    TODO:

    -科学表达中的数字 (n.nnnnnn*10**(exp) —— '10' self.baseDigits[1::-1]/self.to_string(len (self.baseDigits))

    -来自字符串函数。

    -以1-gt;罗马数字为基数?

    -含Agles复合物的repr

    所以我的解决方案是:

    DIGITS = "0123456789abcdefghijklmnopqrstuvwxyz"
    
    
    # note that the order of the digits is reversed for digits before the point
    NO_GROUPING = lambda g: g
    
    concat = "".join
    concat_backwards = lambda g: concat(e for e in reversed(list(g)))
    
    def grouping(length = 3, char = '_'):
        def yieldor(digits):
            i = 0
            for d in digits:
                if i == length:
                    yield char
                    i = 0
                yield d
                i+=1
    
        return yieldor
    
    class Converter:
        def __init__(self, baseDigits: (int, str), beforePoint = NO_GROUPING, afterPoint = NO_GROUPING, decimalPoint = '.', digitPrecision = 16, trimZeros = True):
            if isinstance(baseDigits, int):
                baseDigits = DIGITS[:baseDigits]
            self.baseDigits = baseDigits
    
            self.beforePoint = beforePoint
            self.afterPoint  = afterPoint
    
            self.decimalPoint = decimalPoint
            self.digitPrecision = digitPrecision
            self.trimZeros = trimZeros
    
        def to_string(self, number: (int, float, complex)) -> str:
            if isinstance(number, complex):
                if number.imag == 0:
                    return self.to_string(number.real)
                if number.real == 0:
                    return self.to_string(number.imag) + 'j'
                return "({}+{}j)".format(self.to_string(number.real), self.to_string (number.imag))
            if number < 0:
                return '-' + self.to_string(-number)
            digitCount = len(self.baseDigits)
            if isinstance(number, float):
                # round correctly
                precError=digitCount**-self.digitPrecision
                number+=0.5*precError
                if self.trimZeros:
                    def yieldor(n):
                        p = precError
                        for i in range(self.digitPrecision):
                            if n <= p:
                                return
                            p *= digitCount
                            n *= digitCount
                            digit = int(n)
                            n -= digit
                            yield self.baseDigits[digit]
                else:
                    def yieldor(n):
                        for i in range(self.digitPrecision):
                            n *= digitCount
                            digit = int(n)
                            n -= digit
                            yield self.baseDigits[digit]
    
                a = concat(self.afterPoint(yieldor(number%1)))
    
                return (
                    self.to_string(int(number)) + (a and self.decimalPoint + a)
                )
    
            else: #is int
                if not number: return self.baseDigits[0]
                def yieldor(n):
                    while n:
                        n, digit = divmod(n, digitCount)
                        yield self.baseDigits[digit]
                return concat_backwards(self.beforePoint(yieldor(number)))
    
    # some tests:
    if __name__ == "__main__":
        def conv_test(num, digits, *argv, **kwv):
            print(num, "->", digits if isinstance(digits, int) else "{} ({})".format(len(digits), digits), Converter(digits, *argv, **kwv).to_string(num))
        conv_test(True, "ft")
        conv_test(123, 12, grouping(2))
        conv_test(-0xf00d, 16)
        conv_test(1000, True<<True, grouping(4))
        conv_test(1_000_000, "0+-", beforePoint = grouping(2, '|'))
        conv_test(1.5, 10)
        conv_test(0.999999999, 10, digitPrecision = 8)
        conv_test(-0.1, 10)
    
        import math
        conv_test(math.pi, 10, afterPoint = grouping(5, ' '))
        conv_test(0.123456789, 10, digitPrecision = 6)
    
        grSpc = grouping(1, ' ')
        conv_test(math.e, ["off", "on"], grSpc, grSpc, " dot ", digitPrecision = 7)
    
        conv_test(1 + 1.5j, 10)
    
        conv_test(50j, 10)
    
        conv_test(10.01, '-<>')
    
        # and generate some brainfuck-code here:
        conv_test(1701**42, '+-<>,.][', digitPrecision = 32)
    
        23
  •  -2
  •   Pedram Neo M Hacker    7 年前
    def bn(x,b,ab="0123456789abcdefghijklmnopqrstuvwxyz..."
        a = ""
        while (x>0):
            x,r = divmod(x,n)
            a += ab[r]
        return a[::-1]
    
    bn(2**100, 36)
    

    输出:

    3ewfdnca0n6ld1ggvfgg
    

    要转换成任何基,反转也很容易。