Як перетворити ціле число в рядок у будь-якій базі?


202

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

Пов'язані


5
Дивно, але ніхто не дав рішення, яке працює з довільною великою базою (1023). Якщо вам це потрібно, перевірте моє рішення, яке працює для кожної бази (від 2 до inf) stackoverflow.com/a/28666223/1090562
Сальвадор Далі,

Відповіді:


98

Якщо вам потрібна сумісність із старовинними версіями Python, ви можете використовувати gmpy (що включає швидку, цілком загальну функцію перетворення in -to-string перетворення, і її можна побудувати для таких старовинних версій - можливо, вам доведеться спробувати старіші версії, оскільки останні не перевірені на поважні версії 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)

8
Якраз у (gmpy2) випадку, здається, функціонує Алекс gmpy2.digits(x, base).
mlvljr

2
Мені було донесено, що для деяких випадків потрібна база> 36, і так слід викопуватиdigs = string.digits + string.lowercase + string.uppercase
Павло

4
(або string.digits + string.letters)
kojiro

3
Будь-яка ідея, чому перетворення-база-N-в рядок не включено за замовчуванням у Python? (Це у Javascript.) Так, ми можемо написати власну реалізацію, але я шукав на цьому сайті та в інших місцях, і в багатьох з них є помилки. Краще мати одну перевірену, надійну версію, включену в основний дистрибутив.
Джейсон S

4
@ lordscales91 Ви також можете використовувати те, x //= baseщо поводиться так, як /=у Python 2, упускаючи десяткові. Ця відповідь повинна містити відмову від відповідальності, що це стосується Python 2.
Noumenon

100

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

Який ви згодом можете конвертувати в будь-яку базу


У коледжі я придумав функцію, яка відформатовувала бази нижче 20 у стандартні позначення, а бази 20 і більше в «десятковій крапці з двократкою». Наприклад, int(4545,16)дав "11c1" і int(4545,60)дав "1:15:45". Таким чином, функція виконувала потрійний обов'язок: перетворення у десятковий, комп'ютерний та часовий відмітки.
Пітер

1
Яка зворотна функція для цього методу?
Сохраб T

Це не відповідає на запитання, задане з 3 причин, 1: запитання про існуючу функцію бібліотеки, а не реалізацію 2: запитання задається для рядка, це створює список 3: це не обернено для int (str, основа) вбудований.
підключіть

@plugwash 1) в якийсь момент ви помітите, що іноді не існує вбудованої бібліотечної функції, щоб робити потрібні вам речі, тому вам потрібно написати своє. Якщо ви не погоджуєтеся, опублікуйте власне рішення із вбудованою функцією, яка може перетворити число 10 на базу 577. 2) це пов'язано з нерозумінням того, що означає число в деякій базі. 3) Я закликаю вас трохи подумати, чому база у вашому методі працює лише для n <= 36. Після того, як ви закінчите, буде очевидно, чому моя функція повертає список і має його підпис.
Сальвадор Далі

1
Це не працює для негативних чисел, і я не впевнений, як змусити його працювати, не змінюючи принципово. Може, додавши біт знака 1 або -1 вгорі digits?
wjandrea

89
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

для дуже великих цілих чисел.


5
Елегантний за своєю стислістю Схоже, він працює під python 2.2.3 для негативних чисел. Від'ємне число нескінченно повторюється.
Марк Боргердінг

+1 корисно; виправлена проблема , коли цифри не починаються з «0»
sehe

4
Це виходить з ладу (а), коли база> len(numerals), а (б) num % b, на щастя, < len(numerals). наприклад, хоча numeralsрядок довжиною всього 36 символів, baseN (60, 40) повертається, '1k'тоді як baseN (79, 40) збільшує an IndexError. Обидва повинні викликати якусь помилку. Код слід переглянути, щоб викликати помилку, якщо not 2 <= base <= len(numerals).
Кріс Джонсон

3
@osa, мій погляд на те, що написаний код не вдається дуже погано (мовчки, даючи оманливу відповідь) і його можна легко виправити. Якщо ви говорите, не було б помилки, якби ви знали заздалегідь, напевно, це bне перевищило б len(numerals), ну, удачі вам.
Кріс Джонсон

1
Використання короткого замикання тут видається непотрібним заплутаним ... чому б не просто використовувати оператор if ... рядок return numerals[0] if num == 0 else baseN(num // b, b, numerals).lstrip(numerals[0]) + numerals[num % b]такий же короткий.
Ян Хінкс

83
"{0:b}".format(100) # bin: 1100100
"{0:x}".format(100) # hex: 64
"{0:o}".format(100) # oct: 144

46
Але це лише ті три основи?
Thomas Ahle

3
Так, на жаль, ви не можете вказати користувальницьку базу int. Більше інформації тут: docs.python.org/library/string.html#formatstrings
Rost

3
Це 0зайве. Ось документація на Python 2: docs.python.org/2/library/string.html#format-string-syntax
Євгеній Сергієв,

7
Ви можете досягти тих же результатів з hex(100)[2:], oct(100)[2:]і bin(100)[2:].
Сассан

2
@EvgeniSergeev: Це не потрібно лише на 2.7 / 3.1 +. На 2.6 потрібне чітке положення (або ім'я).
ShadowRanger

21

Чудові відповіді! Я думаю, що відповідь на моє запитання була «ні», я не пропустив явного рішення. Ось функція, яку я буду використовувати, що конденсує хороші ідеї, висловлені у відповідях.

  • дозволити відображення символів, що надаються абонентом (дозволяє базове кодування)
  • перевіряє на мінус та нуль
  • відображає складні числа в кортежі рядків


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


4
Як перетворити вихідний результат нашої функції64 в ціле число?
detly

16

Рекурсивний

Я хотів би спростити в найбільш проголосували відповідь на:

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"

2
Прекрасно реконструйований та без бібліотеки.
Джампаоло Феррадіні

Чи не повинна return BS[0] if not nтоді бути умова зупинки ? Про всяк випадок, якщо ви хочете використовувати модні цифри, як я :)
Арно П

@ArnaudP погодився. Цей для мене працює:return BS[n] if n < b else to_base(n // b) + BN[n % b]
Єнс

15

Python не має вбудованої функції для друку цілого числа у довільній основі. Якщо вам потрібно, вам доведеться написати своє.


13

Ви можете використати для 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.


12

>>> numpy.base_repr(10, base=3) '101'


Приємне рішення. У моєму випадку я уникав нудоти, пов'язаних clacіз завантаженням. Попередньо завантаживши numpy більше, ніж втричі, час простого оцінювання виразів у clac: наприклад, clac 1+1 пішло приблизно від 40 мс до 140 мс.
Марк Боргердінг

1
Зауважте, що numpy.base_repr()в якості основи встановлено обмеження 36. В іншому випадку він кидає aValueError
sbdchd

Що відповідає обмеженню вбудованої функції "int". Більші бази вимагають вирішити, що робити, коли листи закінчуються,
підключіть

4

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

base10toN не враховує випадку num == 0.
Craeft

3

Я зробив для цього пакет піп.

Я рекомендую вам використовувати мій bases.py 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 для того, які бази можуть бути використані

EDIT: pip посилання https://pypi.python.org/pypi/bases.py/0.2.2


Це працює як шарм для відомих баз .
Agi Hammerthief

Це, безумовно, найкраща відповідь! І дякую за упаковку з піпками!
ɹɐʎɯɐʞ

3
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)

вихід:

"1F"


other-baseте саме other - base, що і ви повинні використовуватиother_base
mbomb007

Крім того, це не працює правильно, якщо decimalдорівнює нулю.
mbomb007

1
>>> 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'

1

Рекурсивне рішення для зацікавлених. Звичайно, це не буде працювати з негативними бінарними значеннями. Вам потрібно буде реалізувати Доповнення двох.

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

1
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..."Місії" - знайти все ".

Для кожного N=1,2,3...коду є виділення aN*base**N"mouduling" на b, для b=base**(N+1) якого зріз усіх a більший ніж N, і нарізання всіх a, що їх послідовність менша ніж N, зменшуючи щоразу, коли функція викликається струмом aN*base**N.

База% (база-1) == 1 для цього база ** p% (база-1) == 1 і для цього q * база ^ p% (база-1) == q лише з одним винятком, коли q = база-1 який повертає 0. Щоб виправити це у випадку, коли він повертається 0, функція перевіряє, чи це 0 від початку.


переваги

у цьому зразку є лише одне множення (замість ділення) та деякі мадулі, що відносно займає невелику кількість часу.


1
num = input("number")
power = 0
num = int(num)
while num > 10:
    num = num / 10
    power += 1

print(str(round(num, 2)) + "^" + str(power))

будь-ласка, додайте коротку інформацію про те, що ви зробили спеціальний
ініт

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

1
def base_changer(number,base):
    buff=97+abs(base-10)
    dic={};buff2='';buff3=10
    for i in range(97,buff+1):
        dic[buff3]=chr(i)
        buff3+=1   
    while(number>=base):
        mod=int(number%base)
        number=int(number//base)
        if (mod) in dic.keys():
            buff2+=dic[mod]
            continue
        buff2+=str(mod)
    if (number) in dic.keys():
        buff2+=dic[number]
    else:
        buff2+=str(number)

    return buff2[::-1]   

За допомогою цієї функції ви можете легко перетворити будь-яке десяткове число в улюблену базу.
montaqami

Вам не потрібно коментувати власну відповідь, ви можете просто відредагувати її, щоб додати пояснення.
Почмурник

1

Ось приклад того, як перетворити число будь-якої бази на іншу базу.

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!!!")

0
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)

0

Ще один короткий (і простіше для розуміння 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")

0

Інше рішення, що працює з базою 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

0

Ось рекурсивна версія, яка обробляє підписані цілі числа та власні цифри.

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]

0

Рядки не є єдиним вибором для представлення чисел: ви можете використовувати список цілих чисел для представлення порядку кожної цифри. Їх можна легко перетворити на рядок.

Жодна з відповідей не відкидає базу <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)

Швидкість передачі n_to_baseпорівнянна з strвеликою кількістю (приблизно 0,3 секунди на моїй машині), але якщо порівнювати протиhex ви можете бути здивовані (приблизно на 0,3 м на моїй машині або на 1000 разів швидше). Причина полягає в тому, що велике ціле число зберігається в пам'яті в базі 256 (байт). Кожен байт може бути просто перетворений у двозначний шістнадцятковий рядок. Таке вирівнювання відбувається лише для баз, які мають сили двох, тому існують спеціальні випадки для 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. З цього видно, що остання цифра залежить від суми всіх байтів. Це нелокальне властивість робить те, що ускладнює перетворення в десятковий.


0
def baseConverter(x, b):
    s = ""
    d = string.printable.upper()
    while x > 0:
        s += d[x%b]
        x = x / b
    return s[::-1]

Для python3 ваш код робить це: baseConverter (0, 26) -> '' baseConverter (1, 26) -> '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' Для python2 це робить: baseConverter (0, 26) -> '' baseConverter (1, 26) -> 1 базаConverter (3, 26) -> 3 baseConverter (5, 26) -> 5 baseConverter (26, 26) -> 10 baseConverter (32, 26) -> 16
Drachenfels

0

Ну я особисто використовую цю функцію, написану мною

import string

def to_base(value, base, digits=string.digits+string.ascii_letters):    # converts decimal to base n

    digits_slice = digits[0:base]

    temporary_var = value
    data = [temporary_var]

    while True:
        temporary_var = temporary_var // base
        data.append(temporary_var)
        if temporary_var < base:
            break

    result = ''
    for each_data in data:
        result += digits_slice[each_data % base]
    result = result[::-1]

    return result

Ось як ви можете ним користуватися

print(to_base(7, base=2))

Вихід: "111"

print(to_base(23, base=3))

Вихід: "212"

Будь ласка, не соромтеся запропонувати поліпшення в моєму коді.


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

0

Це старе питання, але я подумав, що поділюсь своїм питанням, оскільки я вважаю, що це дещо простіше, ніж інші відповіді (добре для баз від 2 до 36):

def intStr(n,base=10):
    if n < 0   : return "-" + intStr(-n,base)         # handle negatives
    if n < base: return chr([48,55][n>9] + n)         # 48 => "0"..., 65 => "A"...
    return intStr(n//base,base) + intStr(n%base,base) # recurse for multiple digits

-1

Я не бачив тут жодного перетворювача плаву. І я пропустив групування завжди на три цифри.

РОБИТИ:

-числа в науковому вираженні (n.nnnnnn*10**(exp)-'10' єself.baseDigits[1::-1]/self.to_string(len (self.baseDigits))

-from_string-функція.

-база 1 -> римські числа?

-репр комплексу з алами

Тож ось моє рішення:

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)

-2
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

конвертувати в будь-яку базу, обернено теж легко.


Зрозумів NameError: global name 'n' is not defined. Це divmod(x, n)повинно бути divmod(x, b)?
wjandrea
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.