¿Cómo convertir un entero a una cadena en cualquier base?


203

Python permite la creación fácil de un número entero a partir de una cadena de una base dada a través de

int(str, base). 

Quiero realizar la inversa: creación de una cadena a partir de un entero , es decir, quiero alguna función int2base(num, base), tal que:

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

El nombre de la función / orden de los argumentos no es importante.

Para cualquier número xy base bque int()acepte.

Esta es una función fácil de escribir: de hecho, es más fácil que describirla en esta pregunta. Sin embargo, siento que me falta algo.

Yo sé acerca de las funciones bin, oct, hex, pero no puedo usarlos por varias razones:

  • Esas funciones no están disponibles en versiones anteriores de Python, con las cuales necesito compatibilidad con (2.2)

  • Quiero una solución general que se pueda llamar de la misma manera para diferentes bases

  • Quiero permitir bases que no sean 2, 8, 16

Relacionado


55
Sorprendentemente, nadie dio una solución que funciona con una gran base arbitraria (1023). Si lo necesita, consulte mi solución que funciona para cada base (2 a inf) stackoverflow.com/a/28666223/1090562
Salvador Dali

Respuestas:


98

Si necesita compatibilidad con versiones antiguas de Python, puede usar gmpy (que incluye una función de conversión de int a cadena rápida y completamente general, y puede crearse para tales versiones antiguas; es posible que deba probar versiones anteriores ya que los recientes no han sido probados para versiones venerables de Python y GMP, solo algunos recientes), o, para menor velocidad pero más conveniencia, use el código Python, por ejemplo, más simplemente:

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
Solo en el caso (gmpy2) parece ser la función de la que habla Alex gmpy2.digits(x, base).
mlvljr

2
Me llamaron la atención que algunos casos necesitan una base> 36, por lo que las excavaciones deberían serlodigs = string.digits + string.lowercase + string.uppercase
Paul

44
(o string.digits + string.letters)
kojiro

3
¿Alguna idea de por qué convert-base-N-to-string no se incluye por defecto en Python? (Está en Javascript.) Sí, todos podemos escribir nuestra propia implementación, pero he estado buscando en este sitio y en otros lugares, y muchos de ellos tienen errores. Es mejor tener una versión probada y de buena reputación incluida en la distribución principal.
Jason S

44
@ lordscales91 También puede usar el x //= baseque se comporta como /=en Python 2 al soltar el decimal. Esta respuesta debe incluir un descargo de responsabilidad de que es para Python 2.
Noumenon

100

Sorprendentemente, las personas solo daban soluciones que se convertían en bases pequeñas (más pequeñas que la longitud del alfabeto inglés). No hubo ningún intento de dar una solución que convierta a cualquier base arbitraria de 2 a infinito.

Así que aquí hay una solución súper simple:

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

así que si necesitas convertir un número súper enorme a la base 577 ,

numberToBase(67854 ** 15 - 102, 577), te dará una solución correcta: [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 luego puede convertir a cualquier base que desee


En la universidad se me ocurrió una función que formateaba las bases por debajo de 20 en notación estándar y las bases 20 y más en 'decimal delimitado por dos puntos'. Por ejemplo, int(4545,16)dio "11c1" y int(4545,60)dio "1:15:45". Por lo tanto, la función cumplió tres funciones: la conversión a formatos decimal, computarizado y de marca de tiempo.
Peter Raynham

1
¿Cuál es la función inversa para este método?
Sohrab T

Esto no responde a la pregunta formulada por 3 razones, 1: la pregunta solicitada para una función de biblioteca existente no una implementación 2: la pregunta solicitó una cadena, esto produce una lista 3: esto no es un inverso para el int (str, base) incorporado.
lavar el

@plugwash 1) en algún momento notarás que a veces no hay una función de biblioteca integrada para hacer las cosas que deseas, por lo que debes escribir la tuya propia. Si no está de acuerdo, publique su propia solución con una función integrada que puede convertir un número de base 10 en base 577. 2) Esto se debe a la falta de comprensión de lo que significa un número en alguna base. 3) Le animo a que piense un poco por qué la base en su método funciona solo para n <= 36. Una vez que haya terminado, será obvio por qué mi función devuelve una lista y tiene la firma que tiene.
Salvador Dali

1
Esto no funciona para números negativos, y no estoy seguro de cómo hacerlo funcionar sin cambiarlo fundamentalmente. ¿Quizás agregando un bit de signo, 1 o -1, en la parte superior de 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])

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

Tenga en cuenta que esto puede conducir a

RuntimeError: maximum recursion depth exceeded in cmp

para enteros muy grandes.


55
Elegante en su brevedad. Parece funcionar bajo Python 2.2.3 para enteros no negativos. Un número negativo se repite infinitamente.
Mark Borgerding

+1 útil; solucionó un problema cuando los números no comenzaban con '0'
sehe

44
Esto falla silenciosamente (a) cuando base es> len(numerals), y (b) num % bes, por suerte, < len(numerals). por ejemplo, aunque la numeralscadena tiene solo 36 caracteres de longitud, baseN (60, 40) regresa '1k'mientras que baseN (79, 40) genera un IndexError. Ambos deberían generar algún tipo de error. El código debe revisarse para generar un error si not 2 <= base <= len(numerals).
Chris Johnson

3
@osa, mi punto es que el código tal como está escrito falla de una manera muy mala (en silencio, dando una respuesta engañosa) y podría repararse fácilmente. Si está diciendo que no habría ningún error si supiera de antemano, sin duda, eso bno excedería len(numerals), bueno, buena suerte para usted.
Chris Johnson

1
El uso de cortocircuito aquí parece innecesariamente confuso ... ¿por qué no usar una instrucción if? ... la línea return numerals[0] if num == 0 else baseN(num // b, b, numerals).lstrip(numerals[0]) + numerals[num % b]es igual de breve.
Ian Hincks

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

46
¿Pero solo hace esas tres bases?
Thomas Ahle

3
Sí, desafortunadamente no puede especificar la base int personalizada. Más información está aquí: docs.python.org/library/string.html#formatstrings
Rost

3
El 0es innecesario. Aquí está la documentación de Python 2: docs.python.org/2/library/string.html#format-string-syntax
Evgeni Sergeev

77
Puede lograr los mismos resultados con hex(100)[2:], oct(100)[2:]y bin(100)[2:].
Sassan

2
@EvgeniSergeev: solo es innecesario en 2.7 / 3.1 +. En 2.6, se requiere la posición explícita (o nombre).
ShadowRanger

21

Grandes respuestas! Supongo que la respuesta a mi pregunta fue "no". No me faltaba una solución obvia. Aquí está la función que usaré que condensa las buenas ideas expresadas en las respuestas.

  • permitir el mapeo de caracteres proporcionado por la persona que llama (permite la codificación base64)
  • comprueba negativo y cero
  • mapea números complejos en tuplas de cuerdas


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


44
¿Cómo convierte la salida de base64 de nuestra función a un número entero?
detly

17

Recursivo

Yo simplificaría la respuesta más votada a:

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

Con el mismo consejo para RuntimeError: maximum recursion depth exceeded in cmpenteros muy grandes y números negativos. (Podrías usarsys.setrecursionlimit(new_limit) )

Iterativo

Para evitar problemas de recursividad :

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

2
Bellamente refactorizado y sin biblioteca.
Giampaolo Ferradini

¿No debería ser return BS[0] if not nentonces la condición de parada ? Sólo en caso de que desee utilizar dígitos de lujo, como yo :)
Arnaud P

@ArnaudP estuvo de acuerdo. Este funciona para mí:return BS[n] if n < b else to_base(n // b) + BN[n % b]
Jens

15

Python no tiene una función incorporada para imprimir un número entero en una base arbitraria. Tendrás que escribir el tuyo si quieres.


13

Puedes usarlo baseconv.pydesde mi proyecto: https://github.com/semente/python-baseconv

Uso de la muestra:

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

Hay algunos convertidores bultin como por ejemplo baseconv.base2, baseconv.base16y baseconv.base64.


12

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


Buena solución En mi caso, estaba evitando numpy clacpor problemas de tiempo de carga. La carga previa de numpy más que triplica el tiempo de ejecución de la evaluación de expresión simple en clac: por ejemplo, clac 1+1 pasó de unos 40 ms a 140 ms.
Mark Borgerding

1
Tenga en cuenta que numpy.base_repr()tiene un límite de 36 como base. De lo contrario, lanza unaValueError
sbdchd

Que coincide con la limitación de la función integrada "int". Las bases más grandes requieren decidir qué hacer cuando se
acaban

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

Aquí hay otro del mismo enlace.

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 no tiene en cuenta el caso de num == 0.
Craeft

3

Hice un paquete pip para esto.

Te recomiendo que uses mis bases.py https://github.com/kamijoutouma/bases.py que se inspiró en 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 qué bases son utilizables

EDITAR: enlace pip https://pypi.python.org/pypi/bases.py/0.2.2


Esto funciona como un encanto para las bases conocidas especificadas .
Agi Hammerthief

¡Esta es, de lejos, la mejor respuesta! Y gracias por el empaque de pepita!
ɹɐʎɯɐʞ

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)

salida:

"1F"


other-basees lo mismo que other - base, así que deberías usarother_base
mbomb007

Además, esto no funciona correctamente si decimales cero.
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

Una solución recursiva para los interesados. Por supuesto, esto no funcionará con valores binarios negativos. Tendría que implementar Complemento de dos.

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

explicación

En cualquier base, cada número es igual a a1+a2*base**2+a3*base**3..."La misión" es encontrar todas las "a".

Por cada N=1,2,3...código, se aísla aN*base**Nmediante "mouduling" mediante b, para lo b=base**(N+1) cual se divide todo a 's más grande que N, y se divide todo el a' s que su serial es más pequeño que N disminuyendo a cada vez que la función llama a la funciónaN*base**N .

Base% (base-1) == 1 para ello base ** p% (base-1) == 1 y para ello q * base ^ p% (base-1) == q con una sola excepción cuando q = base-1 que devuelve 0. Para arreglar eso en caso de que devuelva 0, la función está comprobando si es 0 desde el principio.


ventajas

en esta muestra solo hay una multiplicación (en lugar de división) y algunos mudulueses, lo que lleva relativamente poco tiempo.


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

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

agregue información breve sobre lo que hizo especial init
Farhana

Si bien esto podría responder a la pregunta de los autores, carece de algunas palabras explicativas y / o enlaces a la documentación. Los fragmentos de código sin formato no son muy útiles sin algunas frases a su alrededor. También puede encontrar cómo escribir una buena respuesta muy útil. Por favor edite su respuesta.
hola

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]   

En esta función, puede convertir fácilmente cualquier número decimal a su base favorita.
montaqami

No necesita comentar su propia respuesta, solo puede editarla para agregar una explicación.
Pochmurnik

1

Aquí hay un ejemplo de cómo convertir un número de cualquier base a otra 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

Otro corto (y más 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]

Y con el manejo adecuado de excepciones:

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

Otra solución, funciona con las bases 2 a 10, necesita modificaciones para bases más 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]))

Ejemplo:

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

0

Aquí hay una versión recursiva que maneja enteros firmados y 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

Las cadenas no son la única opción para representar números: puede usar una lista de enteros para representar el orden de cada dígito. Esos se pueden convertir fácilmente en una cadena.

Ninguna de las respuestas rechaza base <2; y la mayoría se ejecutará muy lentamente o se bloqueará con desbordamientos de pila para números muy grandes (como 56789 ** 43210). Para evitar tales fallas, reduzca rápidamente así:

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_basees comparable con strgrandes números (aproximadamente 0.3s en mi máquina), pero si compara con hexusted puede sorprenderse (aproximadamente 0.3ms en mi máquina, o 1000 veces más rápido). La razón es porque el entero grande se almacena en la memoria en base 256 (bytes). Cada byte se puede convertir simplemente en una cadena hexadecimal de dos caracteres. Esta alineación solo ocurre para bases que son potencias de dos, razón por la cual hay casos especiales para 2,8 y 16 (y base64, ascii, utf16, utf32).

Considere el último dígito de una cadena decimal. ¿Cómo se relaciona con la secuencia de bytes que forma su número entero? Vamos a etiquetar los bytes s[i]con s[0]el menos significativo (little endian). Entonces el último dígito es sum([s[i]*(256**i) % 10 for i in range(n)]). Bueno, sucede que 256 ** i termina con un 6 para i> 0 (6 * 6 = 36) de modo que el último dígito es (s[0]*5 + sum(s)*6)%10. A partir de esto, puede ver que el último dígito depende de la suma de todos los bytes. Esta propiedad no local es lo que hace que la conversión a decimal sea más difícil.


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, su código hace esto: baseConverter (0, 26) -> '' baseConverter (1, 26) -> '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001' para base piton2). -> 1 convertidor base (3, 26) -> convertidor 3 base (5, 26) -> convertidor 5 base (26, 26) -> convertidor 10 base (32, 26) -> 16
Drachenfels

0

Bueno, yo personalmente uso esta función, escrita por mí

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

Así es como puedes usarlo

print(to_base(7, base=2))

Salida: "111"

print(to_base(23, base=3))

Salida: "212"

Por favor, siéntase libre de sugerir mejoras en mi 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 es una vieja pregunta, pero pensé que compartiría mi opinión al respecto, ya que siento que es algo más simple que otras respuestas (bueno para bases del 2 al 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

No he visto ningún convertidor de flotador aquí. Y me perdí la agrupación por siempre tres dígitos.

QUE HACER:

-números en expresión científica (n.nnnnnn*10**(exp)- el '10'esself.baseDigits[1::-1]/self.to_string(len (self.baseDigits))

-from_string-function.

-base 1 -> números romanos?

-repr de complejo con agles

Así que aquí está mi solución:

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)

salida:

3ewfdnca0n6ld1ggvfgg

convertir a cualquier base, inversa también es fácil.


Got NameError: global name 'n' is not defined. Se divmod(x, n)supone que es divmod(x, b)?
wjandrea
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.