Как преобразовать целое число в строку в любой базе?


203

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 до инф) stackoverflow.com/a/28666223/1090562
Сальвадор Дали,

Ответы:


98

Если вам нужна совместимость с древними версиями 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)

8
Просто в (gmpy2) случае, о чем говорит Алекс, похоже gmpy2.digits(x, base).
mlvljr

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

4
(или string.digits + string.letters)
Кодзиро

3
Любая идея, почему convert-base-N-to-string не включена по умолчанию в Python? (Это в Javascript.) Да, мы все можем написать свою собственную реализацию, но я искал на этом сайте и в других местах, и у многих из них есть ошибки. Лучше иметь одну проверенную, уважаемую версию, включенную в основной дистрибутив.
Джейсон С

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
Какова обратная функция для этого метода?
Сохраб Т

Это не отвечает на вопрос, заданный по 3 причинам: 1: вопрос, заданный для существующей библиотечной функции, а не для реализации 2: вопрос, заданный для строки, это создает список 3: это не обратное значение для int (str, база) встроенная.
plugwash

@plugwash 1) в какой-то момент вы заметите, что иногда нет встроенной библиотечной функции, которая делает то, что вы хотите, поэтому вам нужно написать свою собственную. Если вы не согласны, опубликуйте собственное решение со встроенной функцией, которая может преобразовать число 10 в базу 577. 2) Это связано с отсутствием понимания, что означает число в некоторой базе. 3) Я призываю вас немного подумать, почему base в вашем методе работает только для 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»
смотрите

4
Это происходит молча (а), когда base> len(numerals), и (b) num % b, к счастью, < len(numerals). Например, хотя numeralsдлина строки составляет всего 36 символов, baseN (60, 40) возвращается, '1k'а baseN (79, 40) вызывает значение 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
Но это только те три базы?
Томас Але

3
Да, к сожалению, вы не можете указать пользовательскую базу int. Более подробная информация здесь: docs.python.org/library/string.html#formatstrings
Рост

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

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

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


4
Как преобразовать вывод base64 нашей функции обратно в целое число?
детально

18

рекурсивный

Я хотел бы упростить в наиболее проголосовали ответ на:

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тогда условие остановки ? На всякий случай, если вы хотите использовать причудливые цифры, как я :)
Arnaud P

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

Есть несколько конвертеров bultin как например 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. В противном случае он выдаетValueError
sbdchd

Что соответствует ограничению встроенной функции "int". Большие базы требуют решения, что делать, когда буквы заканчиваются,
plugwash

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

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

Я рекомендую вам использовать мой 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 чтобы узнать, какие базы можно использовать

РЕДАКТИРОВАТЬ: 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) которого все срезы больше, чем N, и срезание всех a, что их серийный номер меньше N, уменьшая каждый раз, когда функция вызывается током aN*base**N.

Base% (base-1) == 1 для этого base ** p% (base-1) == 1 и для этого q * base ^ p% (base-1) == q только с одним исключением, когда q = base-1 который возвращает 0. Чтобы исправить это в случае, если он возвращает 0, функция проверяет, равен ли он 0 с самого начала.


преимущества

в этом примере есть только одно умножение (вместо деления) и несколько moudulueses, что относительно занимает небольшое количество времени.


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

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

пожалуйста, добавьте краткую информацию о том, что вы сделали специальным init
Фархана

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

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]   

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

Вам не нужно комментировать свой собственный ответ, вы можете просто отредактировать его, чтобы добавить объяснение.
Почмурник

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

Еще один короткий (и более понятный ИМО):

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)

Speedwise, 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) -> '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001' Для python2 он делает это: baseConverter (0, 26) -> '' baseConverter (1, 26) -> 1 baseConverter (3, 26) -> 3 baseConverter (5, 26) -> 5 baseConverter (26, 26) -> 10 baseConverter (32, 26) -> 16
Драхенфельс

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)?
17
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.