Как преобразовать целое число в любой базе в строку? - PullRequest
177 голосов
/ 15 февраля 2010

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

Связанные

Ответы [ 24 ]

87 голосов
/ 15 февраля 2010
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

для очень больших целых чисел.

86 голосов
/ 23 февраля 2015

Удивительно, но люди давали только решения, которые конвертировались в маленькие базы (меньше длины английского алфавита). Не было попыток дать решение, которое преобразуется в любую произвольную базу от 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]

Который вы можете позже преобразовать в любую базу, которую хотите

84 голосов
/ 15 февраля 2010

Если вам нужна совместимость с древними версиями Python, вы можете использовать gmpy (который включает в себя быструю, полностью общую функцию преобразования в строку и может быть построен для таких древних версий - - вам может понадобиться попробовать более старые выпуски, так как последние не были протестированы для почтенных выпусков Python и GMP, только несколько последних), или, для меньшей скорости, но большего удобства, используйте код Python - например, наиболее просто:

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)
70 голосов
/ 05 сентября 2010
"{0:b}".format(100) # bin: 1100100
"{0:x}".format(100) # hex: 64
"{0:o}".format(100) # oct: 144
20 голосов
/ 15 февраля 2010

Отличные ответы! Я думаю, что ответом на мой вопрос было «нет», я не упустил какое-то очевидное решение. Вот функция, которую я буду использовать, которая объединяет хорошие идеи, выраженные в ответах.

  • разрешить сопоставление символов, предоставляемое абонентом (позволяет кодировать 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

15 голосов
/ 15 февраля 2010

Python не имеет встроенной функции для печати целого числа в произвольной базе. Вы должны написать свой собственный, если хотите.

13 голосов
/ 26 сентября 2012

Вы можете использовать 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'

Существует несколько конвертеров, например, baseconv.base2, baseconv.base16 и baseconv.base64.

7 голосов
/ 07 декабря 2018

Рекурсивный

Я бы упростил ответ с наибольшим количеством голосов до:

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"
4 голосов
/ 15 февраля 2010

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
4 голосов
/ 27 мая 2015

Я сделал для этого пакет в пипсах.

Я рекомендую вам использовать мой Base.py https://github.com/kamijoutouma/bases.py, который был вдохновлен Base.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 для каких баз можно использовать

EDIT: pip link https://pypi.python.org/pypi/bases.py/0.2.2

...