Como converter um número inteiro em uma string em qualquer base?


202

O Python permite a fácil criação de um número inteiro a partir de uma sequência de uma determinada base via

int(str, base). 

Eu quero executar o inverso: criação de uma string a partir de um número inteiro , ou seja, eu quero alguma função int2base(num, base), como:

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

A ordem do nome / argumento da função não é importante.

Para qualquer número xe base bque int()aceite.

Essa é uma função fácil de escrever: na verdade, é mais fácil do que descrevê-la nesta pergunta. No entanto, sinto que devo estar perdendo alguma coisa.

Eu sei sobre as funções bin, oct, hex, mas não pode usá-los por algumas razões:

  • Essas funções não estão disponíveis em versões mais antigas do Python, com as quais eu preciso de compatibilidade com (2.2)

  • Eu quero uma solução geral que possa ser chamada da mesma maneira para bases diferentes

  • Quero permitir bases diferentes de 2, 8, 16

Relacionado


5
Surpreendentemente, ninguém deu uma solução que funcione com grande base arbitrária (1023). Se você precisar dele, verificar a minha solução que funciona para cada base (2 a inf) stackoverflow.com/a/28666223/1090562
Salvador Dali

Respostas:


98

Se você precisar de compatibilidade com versões antigas do Python, poderá usar o gmpy (que inclui uma função de conversão int-to-string rápida e completamente geral e pode ser construído para essas versões antigas - você pode precisar tentar versões mais antigas, pois os mais recentes não foram testados para veneráveis ​​lançamentos em Python e GMP, apenas um pouco recentes) ou, para menos velocidade, mas com mais comodidade, use o código Python - por exemplo, mais simplesmente:

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
Apenas no caso (gmpy2), a função de que Alex fala parece ser gmpy2.digits(x, base).
mlvljr

2
Foi trazido à minha atenção que alguns casos precisam de uma base> 36 e assim cava deve serdigs = string.digits + string.lowercase + string.uppercase
Paul

4
(ou string.digits + string.letters)
kojiro 25/09

3
Alguma idéia de por que o convert-base-N-to-string não está incluído por padrão no Python? (Está em Javascript.) Sim, todos nós podemos escrever nossa própria implementação, mas eu tenho pesquisado neste site e em outros lugares, e muitos deles têm bugs. É melhor ter uma versão testada e respeitável incluída na distribuição principal.
Jason S

4
@ lordscales91 Você também pode usar o x //= baseque se comporta como /=no Python 2 ao largar o decimal. Esta resposta deve incluir um aviso de isenção de responsabilidade de que é para o Python 2. #
986

100

Surpreendentemente, as pessoas estavam dando apenas soluções que se convertem em pequenas bases (menores que o comprimento do alfabeto inglês). Não houve tentativa de fornecer uma solução que se converta em qualquer base arbitrária de 2 para o infinito.

Então, aqui está uma solução super simples:

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

então, se você precisar converter um número super enorme para a base 577,

numberToBase(67854 ** 15 - 102, 577), Lhe dará uma solução correta: [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],

Que você pode converter posteriormente para qualquer base que desejar


Na faculdade, criei uma função que formatava bases abaixo de 20 em notação padrão, e as bases 20 e mais em 'decimal delimitado por dois pontos'. Por exemplo, int(4545,16)deu "11c1" e int(4545,60)deu "1:15:45". Assim, a função triplicou: converter para formatos decimal, computadorizado e de carimbo de data / hora.
Peter Raynham

1
Qual é a função inversa para este método?
precisa

Isso não responde à pergunta feita por três razões, 1: a pergunta solicitada para uma biblioteca existente não é uma implementação 2: a pergunta solicitada por uma cadeia de caracteres, isso produz uma lista 3: isso não é inverso para o int (str, base) embutido.
plugwash 18/01

@plugwash 1) Em algum momento, você notará que, às vezes, não há uma função de biblioteca interna para fazer as coisas que você deseja, então você precisa escrever sua própria. Se você não concordar, publique sua própria solução com uma função interna que pode converter um número base 10 em base 577. 2) isso se deve à falta de compreensão do significado de um número em alguma base. 3) Convido você a pensar um pouco por que a base no seu método funciona apenas para n <= 36. Quando terminar, será óbvio por que minha função retorna uma lista e tem a assinatura que possui.
Salvador Dali

1
Isso não funciona para números negativos, e não tenho certeza de como fazê-lo funcionar sem alterá-lo fundamentalmente. Talvez adicionando um bit de sinal, 1 ou -1, na parte superior de digits?
wjandrea 28/04

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

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

Esteja ciente de que isso pode levar a

RuntimeError: maximum recursion depth exceeded in cmp

para números inteiros muito grandes.


5
Elegante em sua brevidade. Parece funcionar no python 2.2.3 para números inteiros não negativos. Um número negativo se repete infinitamente.
Mark Borgerding

+1 útil; Corrigido um problema quando os números não começavam com '0'
sehe 14/09

4
Isso falha silenciosamente (a) quando a base é> len(numerals)e (b) num % bé, por sorte, < len(numerals). por exemplo, embora a numeralsstring tenha apenas 36 caracteres, a baseN (60, 40) retorna '1k'enquanto a baseN (79, 40) gera um IndexError. Ambos devem gerar algum tipo de erro. O código deve ser revisado para gerar um erro se not 2 <= base <= len(numerals).
Chris Johnson

3
@osa, meu argumento é que o código conforme está escrito falha de uma maneira muito ruim (silenciosamente, dando uma resposta enganosa) e pode ser corrigido facilmente. Se você está dizendo que não haveria erro se soubesse com antecedência, com certeza, isso bnão excederia len(numerals), bem, boa sorte para você.
Chris Johnson

1
O uso de curto-circuito aqui parece desnecessariamente confuso ... por que não usar apenas uma declaração if ... a linha return numerals[0] if num == 0 else baseN(num // b, b, numerals).lstrip(numerals[0]) + numerals[num % b]é tão breve.
21818 Ian Hincks #

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

46
Mas apenas essas três bases?
Thomas Ahle

3
Sim, infelizmente você não pode especificar uma base int personalizada. Mais informações estão aqui: docs.python.org/library/string.html#formatstrings
Rost

3
O 0é desnecessário. Aqui está a documentação do Python 2: docs.python.org/2/library/string.html#format-string-syntax
Evgeni Sergeev

7
Você pode obter os mesmos resultados com hex(100)[2:], oct(100)[2:]e bin(100)[2:].
Sassan

2
@EvgeniSergeev: Só é desnecessário no 2.7 / 3.1 +. No 2.6, a posição explícita (ou nome) é necessária.
ShadowRanger

21

Ótimas respostas! Acho que a resposta para minha pergunta foi "não". Não estava faltando uma solução óbvia. Aqui está a função que usarei que condensa as boas idéias expressas nas respostas.

  • permite o mapeamento de caracteres fornecido pelo chamador (permite codificação base64)
  • verifica se há negativo e zero
  • mapeia números complexos em tuplas de strings


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
Como você converte a saída base64 da nossa função em um número inteiro?
detly 26/10/10

16

Recursivo

Eu iria simplificar a resposta mais votada para:

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

Com o mesmo conselho para RuntimeError: maximum recursion depth exceeded in cmpnúmeros inteiros muito grandes e números negativos. (Você poderia usar sys.setrecursionlimit(new_limit))

Iterativo

Para evitar problemas de recursão :

BS="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
def to_base(s, b):
    res = ""
    while s:
        res+=BS[s%b]
        s//= b
    return res[::-1] or "0"

2
Maravilhosamente refatorado, e sem biblioteca.
Giampaolo Ferradini

A condição de parada não deveria ser return BS[0] if not nentão? Apenas no caso de você querer usar dígitos extravagantes, como eu faço :)
Arnaud P

@ArnaudP concordou. Este funciona para mim:return BS[n] if n < b else to_base(n // b) + BN[n % b]
Jens

15

O Python não possui uma função interna para imprimir um número inteiro em uma base arbitrária. Você terá que escrever o seu próprio, se quiser.


13

Você poderia usar baseconv.pydo meu projeto: https://github.com/semente/python-baseconv

Uso da amostra:

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

Existem alguns conversores de bultina, como por exemplo baseconv.base2, baseconv.base16e baseconv.base64.


12

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


Ótima solução. No meu caso, eu evitava ficar entorpecido clacdevido a preocupações com o tempo de carregamento. O pré-carregamento do numpy mais do que triplica o tempo de execução da avaliação de expressões simples no clac: por exemplo, clac 1+1 passou de cerca de 40ms para 140ms.
precisa

1
Observe que numpy.base_repr()tem um limite de 36 como base. Caso contrário, ele lança umValueError
sbdchd 23/10/19

Que corresponde à limitação da função "int" incorporada. Bases maiores exigem decidir o que fazer quando as letras
acabarem

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

Aqui está outro do mesmo link

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 não conta para o caso de num == 0.
Craeft

3

Eu fiz um pacote de pip para isso.

Eu recomendo que você use minhas bases.py https://github.com/kamijoutouma/bases.py, que foi inspirada em 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

consulte https://github.com/kamijoutouma/bases.py#known-basesalphabets para saber quais bases são utilizáveis

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


Isso funciona como um encanto para as bases conhecidas especificadas .
Agi Hammerthief

Esta é de longe a melhor resposta! E obrigado pela embalagem pip!
ɹɐʎɯɐʞ

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)

resultado:

"1F"


other-baseé o mesmo que other - base, então você deve usar #other_base
mbomb007

Além disso, isso não funciona corretamente se decimalfor zero.
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

Uma solução recursiva para os interessados. Obviamente, isso não funcionará com valores binários negativos. Você precisaria implementar o Complemento Dois.

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

explicação

Em qualquer base, todo número é igual a a1+a2*base**2+a3*base**3..."missão" é encontrar todos os a.

Para cada N=1,2,3...código, o aN*base**N"mouduling" é isolado por "b", para b=base**(N+1) qual fatia todos a é maior que N e fatiga todos os "a" de que sua série é menor que N diminuindo a cada vez que a função é chamada pela corrente aN*base**N.

Base% (base-1) == 1 para a base ** p% (base-1) == 1 e, portanto, q * base ^ p% (base-1) == q com apenas uma exceção quando q = base-1 que retorna 0. Para corrigir que, no caso de retornar 0, a função está verificando se é 0 desde o início.


vantagens

nesta amostra, existem apenas uma multiplicação (em vez de divisão) e algumas mudas, que levam relativamente pouco tempo.


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

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

por favor, adicione algumas informações breves que o que você fez init especial
Farhana

Embora isso possa responder à pergunta dos autores, faltam algumas palavras explicativas e / ou links para a documentação. Os trechos de código bruto não são muito úteis sem algumas frases ao seu redor. Você também pode descobrir como escrever uma boa resposta muito útil. Edite sua resposta.
Hellow

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]   

Nesta função, você pode converter facilmente qualquer número decimal na sua base favorita.
montaqami

Você não precisa comentar sua própria resposta, basta editá-la para adicionar uma explicação.
Pochmurnik 08/09/19

1

Aqui está um exemplo de como converter um número de qualquer base em outra base.

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

Outro pequeno (e mais fácil de entender):

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

E com manipulação de exceção adequada:

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

Outra solução, funciona com as bases 2 a 10, precisa ser modificada para bases mais altas:

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

Exemplo:

n2b(10,2) => '10100'
int(n2b(10,2),2) => 10

0

Aqui está uma versão recursiva que lida com números inteiros assinados e dígitos personalizados.

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

Strings não são a única opção para representar números: você pode usar uma lista de números inteiros para representar a ordem de cada dígito. Aqueles podem ser facilmente convertidos em uma string.

Nenhuma das respostas rejeita a base <2; e a maioria será executada muito lentamente ou travará com estouros de pilha para números muito grandes (como 56789 ** 43210). Para evitar essas falhas, reduza rapidamente assim:

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é comparável stra números grandes (cerca de 0,3s na minha máquina), mas se você comparar comhex você, poderá se surpreender (cerca de 0,3ms na minha máquina ou 1000x mais rápido). O motivo é porque o número inteiro grande é armazenado na memória na base 256 (bytes). Cada byte pode simplesmente ser convertido em uma sequência hexadecimal de dois caracteres. Esse alinhamento ocorre apenas para bases com potências de dois, e é por isso que existem casos especiais para 2,8 e 16 (e base64, ascii, utf16, utf32).

Considere o último dígito de uma sequência decimal. Como isso se relaciona com a sequência de bytes que forma seu número inteiro? Vamos rotular os bytes s[i]como s[0]sendo os menos significativos (little endian). Então o último dígito é sum([s[i]*(256**i) % 10 for i in range(n)]). Bem, acontece que 256 ** i termina com um 6 para i> 0 (6 * 6 = 36), de modo que o último dígito é (s[0]*5 + sum(s)*6)%10. A partir disso, você pode ver que o último dígito depende da soma de todos os bytes. Essa propriedade não-local é o que dificulta a conversão para decimal.


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

Para python3, seu código faz isso: baseConverter (0, 26) -> '' baseConverter (1, 26) -> '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001' Para python2, ele faz isso: baseConverter (0, 26) -> '' baseConverter (1, 26) -> 1 baseConverter (3, 26) -> 3 baseConverter (5, 26) -> 5 baseConverter (26, 26) -> 10 baseConverter (32, 26) -> 16
Drachenfels

0

Bem, eu pessoalmente uso essa função, escrita por mim

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

É assim que você pode usá-lo

print(to_base(7, base=2))

Resultado: "111"

print(to_base(23, base=3))

Resultado: "212"

Por favor, sinta-se livre para sugerir melhorias no meu código.


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

0

Esta é uma pergunta antiga, mas pensei em compartilhar minha opinião, pois acho que é um pouco mais simples que outras respostas (boas para bases de 2 a 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

Eu não vi nenhum conversor de flutuador aqui. E eu perdi o agrupamento por sempre três dígitos.

FAÇAM:

-números na expressão científica (n.nnnnnn*10**(exp)- '10'éself.baseDigits[1::-1]/self.to_string(len (self.baseDigits))

-from_string-function.

-base 1 -> números romanos?

-repr de complexo com agles

Então aqui está a minha solução:

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)

resultado:

3ewfdnca0n6ld1ggvfgg

para converter para qualquer base, o inverso também é fácil.


Got NameError: global name 'n' is not defined. É divmod(x, n)suposto ser divmod(x, b)?
wjandrea
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.