Comment convertir un entier dans n'importe quelle base en chaîne de caractères?

Python permet la création facile d'un entier à partir d'une chaîne d'une base donnée via

int(str, base). 

je veux effectuer l'inverse: création d'une chaîne à partir d'un entier , i.e. je veux une fonction int2base(num, base) , telle que:

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

la fonction Nom/ordre d'argument est sans importance.

pour tout numéro x et base b que int() acceptera.

c'est une fonction facile à écrire: en fait c'est plus facile que de la décrire dans cette question. Cependant, j'ai l'impression que je manque quelque chose.

je connais les fonctions bin , oct , hex , mais je ne peut pas les utiliser pour quelques raisons:

  • ces fonctions ne sont pas disponibles sur les anciennes versions de Python, avec lesquelles j'ai besoin de compatibilité avec (2.2)

  • je veux une solution générale qui peut être appelée de la même façon pour différentes bases

  • je veux autoriser des bases autres que 2, 8, 16

Liées

  • Python élégant inverse de la fonction de type int(string, base)
  • système entier à base-x utilisant la récursion en python
  • conversion de Base 62 en Python
  • comment convertir un entier en la chaîne la plus courte url-safe en Python?
161
demandé sur Community 2010-02-15 19:33:01

21 réponses

si vous avez besoin de compatibilité avec les anciennes versions de Python, vous pouvez utiliser gmpy (qui inclut une fonction de conversion rapide, complètement générale int-to-string, et peut être construit pour ces anciennes versions -- vous pouvez avoir besoin d'essayer des versions plus anciennes puisque les récentes n'ont pas été testées pour les versions venerable Python et GMP, seulement un peu plus récentes), ou, pour moins de vitesse mais plus de commodité, utiliser le code Python -- par exemple, le plus simplement:

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)
80
répondu Alex Martelli 2018-03-13 00:18:51
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 /

s'il vous Plaît être conscient que cela peut conduire à des

RuntimeError: maximum recursion depth exceeded in cmp

pour de très grands nombres entiers.

83
répondu jellyfishtree 2016-11-11 18:38:33

étonnamment, les gens ne donnaient que des solutions qui se convertissent en petites bases (plus petite que la longueur de l'alphabet anglais). Il n'y avait aucune tentative de donner une solution qui convertit à n'importe quelle base arbitraire de 2 à l'infini.

voici donc une solution très simple:

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

donc si vous avez besoin de convertir un nombre super énorme à la base 577 ,

numberToBase(67854 ** 15 - 102, 577) , vous donnera une solution correcte: [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 vous pouvez convertir plus tard à n'importe quelle base que vous voulez

74
répondu Salvador Dali 2018-08-20 19:38:52
"{0:b}".format(100) # bin: 1100100
"{0:x}".format(100) # hex: 64
"{0:o}".format(100) # oct: 144
61
répondu Rost 2010-09-05 19:23:40

de Grandes réponses! Je suppose que la réponse à ma question était "Non". Je ne manquais pas une solution évidente. Voici la fonction que j'utiliserai qui condense les bonnes idées exprimées dans les réponses.

  • permettre la mise en correspondance des caractères fournie par l'appelant (permet l'encodage base64)
  • contrôles pour négatif et zéro
  • cartes des nombres complexes dans des tuples de chaînes


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

20
répondu Mark Borgerding 2014-10-22 13:55:36

Python n'a pas de fonction intégrée pour imprimer un entier dans une base arbitraire. Vous devrez écrire votre propre si vous le souhaitez.

13
répondu Mike Graham 2010-02-15 16:39:09

vous pouvez utiliser baseconv.py de mon projet: https://github.com/semente/python-baseconv

exemple d'utilisation:

>>> 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('34')
'$-22'
>>> base11.decode('$-22')
'34'

il y a quelques convertisseurs bultin comme par exemple baseconv.base2 , baseconv.base16 et baseconv.base64 .

13
répondu semente 2018-06-13 05:19:38

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

En voici un autre du même lien

def baseconvert(n, base):
    """convert positive decimal integer n to equivalent in another base (2-36)"""

    digits = "0123456789abcdefghijklmnopqrstuvwxyz"

    try:
        n = int(n)
        base = int(base)
    except:
        return ""

    if n < 0 or base < 2 or base > 36:
        return ""

    s = ""
    while 1:
        r = n % base
        s = digits[r] + s
        n = n / base
        if n == 0:
            break

    return s
4
répondu John La Rooy 2010-02-15 16:40:00

j'ai fait un paquet pip pour ça.

je vous recommande d'utiliser mon bases.py https://github.com/kamijoutouma/bases.py qui s'inspire des 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

se référer à https://github.com/kamijoutouma/bases.py#known-basesalphabets pour quelles bases sont utilisables

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

3
répondu Belldandu 2017-01-21 00:38:46
def base(decimal ,base) :
    list = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    other_base = ""
    while decimal != 0 :
        other_base = list[decimal % base] + other_base
        decimal    = decimal / base
    return other_base

print base(31 ,16)

sortie:

"1"

2
répondu mukundan 2016-04-09 10:03:22
>>> 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
répondu SilentGhost 2010-02-15 18:21:43

une solution récursive pour les intéressés. Bien sûr, cela ne fonctionnera pas avec des valeurs binaires négatives. Vous devez mettre en œuvre le complément de Two.

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
répondu Mr. Polywhirl 2015-01-27 13:16:00
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()

explication

dans n'importe quelle base chaque nombre est égal à a1+a2*base**2+a3*base**3... la" mission " est de trouver tous les a 's.

pour chaque N=1,2,3... le code isole le aN*base**N par" mouduling "par b pour b=base**(N+1) qui tranche tout a 'S Plus grand que N, et tranchant tout a 'S que leur série est plus petite que N en diminuant un chaque fois que le func est appelé par le courant aN*base**N .

de Base%(base-1)==1 à cet effet de base**p%(base-1)==1 et donc q*^p%(base-1)==q avec une seule exception, lorsque q=base 1 qui renvoie 0. Pour corriger cela dans le cas où il retourne 0 la func vérifie est-il 0 de la mendiante.


avantages

dans cet échantillon, il n'y a qu'une seule multiplication (au lieu d'une division) et quelques mouduluses qui prennent relativement peu de temps.

1
répondu Shu ba 2016-04-26 22:26:41
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
répondu nameisnotphil 2015-08-10 22:01:40

un autre court (et plus facile à comprendre imo):

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

et à l'exception de la manipulation appropriée:

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
répondu Ariel 2016-02-21 16:38:02

une autre solution, fonctionne avec la base 2 à 10, a besoin de modification pour les bases supérieures:

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

exemple:

n2b(10,2) => '10100'
int(n2b(10,2),2) => 10
0
répondu Stanislav 2016-05-19 17:44:35

Voici une version récursive qui traite les entiers signés et les chiffres personnalisés.

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
répondu Antoine Pinsard 2016-12-09 08:53:51
def baseConverter(x, b):
    s = ""
    d = string.printable.upper()
    while x > 0:
        s += d[x%b]
        x = x / b
    return s[::-1]
0
répondu gjivanya 2017-02-20 03:21:41
Les chaînes

ne sont pas le seul choix pour représenter des nombres: vous pouvez utiliser une liste d'entiers pour représenter l'ordre de chaque chiffre. Ceux-ci peuvent facilement être convertis en chaîne.

aucune des réponses ne rejette la base < 2; et la plupart s'exécuteront très lentement ou s'écraseront avec des dépassements de pile pour des nombres très grands (tels que 56789 ** 43210). Pour éviter de telles défaillances, réduire rapidement comme ceci:

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 est comparable avec str pour les grands nombres (environ 0,3 s sur ma machine), mais si vous comparez avec hex vous pouvez être surpris (environ 0,3 ms sur ma machine, ou 1000x plus rapide). La raison en est que le grand entier est stocké en mémoire dans la base 256 (bytes). Chaque octet peut simplement être converti en deux caractères chaîne hexadécimale. Cet alignement se produit seulement pour les bases qui sont des puissances de deux, c'est pourquoi il y a des cas spéciaux pour 2,8, et 16 (et base64, ascii, utf16, utf32).

considère le dernier chiffre d'une chaîne décimale. Comment est-il lié à la séquence d'octets qui forme son entier? Appelons les octets s[i] avec s[0] étant le moins significatif (little endian). Le dernier chiffre est sum([s[i]*(256**i) % 10 for i in range(n)]) . Il se trouve que 256* * I se termine par un 6 pour i > 0 (6*6=36) de sorte que le dernier chiffre est (s[0]*5 + sum(s)*6)%10 . À partir de là, vous pouvez voir que le dernier chiffre dépend de la somme de tous les octets. Cette propriété non locale est ce qui rend conversion en décimal plus difficile.

-1
répondu colski 2017-01-20 14:54:53

Je n'ai pas vu de convertisseurs de flotteur ici. Et j'ai raté le regroupement pour toujours trois chiffres.

TODO:

- nombres dans l'expression scientifique (n.nnnnnn*10**(exp) -- le '10' est self.baseDigits[1::-1]/self.to_string(len (self.baseDigits))

-from_string-fonction.

- base 1 - > nombres romains?

- reprise de complex with agles

voici donc ma solution:

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)
-1
répondu cmdLP 2017-06-28 11:35:25
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)

sortie:

3ewfdnca0n6ld1ggvfgg

pour convertir à n'importe quelle base, l'inverse est facile aussi.

-2
répondu Rogério Duarte 2017-12-23 08:36:05