Convertir en binaire et conserver les zéros non significatifs en Python


154

J'essaie de convertir un entier en binaire en utilisant la fonction bin () en Python. Cependant, il supprime toujours les zéros non significatifs, dont j'ai réellement besoin, de sorte que le résultat soit toujours 8 bits:

Exemple:

bin(1) -> 0b1

# What I would like:
bin(1) -> 0b00000001

Y-a-t'il une façon de le faire?


Voir aussi: Python int en binaire? , en particulier ma réponse avec la représentation n-bit. Pas exactement la même chose, mais je suis arrivé à cette question en cherchant ma réponse ...
Martin Thoma

Réponses:


220

Utilisez la format()fonction :

>>> format(14, '#010b')
'0b00001110'

La format()fonction formate simplement l'entrée en suivant le mini-langage Format Specification . Le #fait que le format inclut le 0bpréfixe, et la 010taille formate la sortie pour qu'elle tienne dans une largeur de 10 caractères, avec un 0remplissage; 2 caractères pour le 0bpréfixe, les 8 autres pour les chiffres binaires.

C'est l'option la plus compacte et la plus directe.

Si vous mettez le résultat dans une chaîne plus grande, utilisez un littéral de chaîne formaté (3.6+) ou utilisez str.format()et mettez le deuxième argument de la format()fonction après les deux points de l'espace réservé {:..}:

>>> value = 14
>>> f'The produced output, in binary, is: {value:#010b}'
'The produced output, in binary, is: 0b00001110'
>>> 'The produced output, in binary, is: {:#010b}'.format(value)
'The produced output, in binary, is: 0b00001110'

En l'occurrence, même pour simplement formater une seule valeur (donc sans mettre le résultat dans une chaîne plus grande), utiliser une chaîne littérale formatée est plus rapide que d'utiliser format():

>>> import timeit
>>> timeit.timeit("f_(v, '#010b')", "v = 14; f_ = format")  # use a local for performance
0.40298633499332936
>>> timeit.timeit("f'{v:#010b}'", "v = 14")
0.2850222919951193

Mais je n'utiliserais cela que si les performances dans une boucle serrée comptent, car elles format(...)communiquent mieux l'intention.

Si vous ne vouliez pas le 0bpréfixe, déposez simplement le #et ajustez la longueur du champ:

>>> format(14, '08b')
'00001110'

3
Exactement ce que je cherchais, ce formatage m'est vraiment utile. J'ai commencé à apprendre la manipulation de bits et je cherchais sur Google le formatage des bits pour les nombres en Python. J'ai trouvé ça. Je vous remercie.
kratostoical

Fonctionne bien. Peut devenir un peu encombrant cependant. format(192,'08b')+'.'+format(0,'08b')+'.'+format(2,'08b')+'.'+format(33,'08b') 11000000.00000000.00000010.00100001
voix

@ tjt263: C'est pourquoi j'indique explicitement que si vous mettez le résultat dans une chaîne plus grande, utilisez une chaîne littérale formatée (3.6+) ou utilisez str.format()et mettez le deuxième argument pour la fonction format () après les deux points de l'espace réservé {:..}:
Martijn Pieters

1
@ tjt263: par exemple utiliser f"{192:08b}.{0:08b}.{2:08b}.{33:08b}".
Martijn Pieters

Très agréable. Je n'aurais jamais su que c'est ce que vous vouliez dire par la seule explication. Mais maintenant que j'ai vu votre exemple, je ne l'oublierai probablement jamais. À votre santé.
voix

115
>>> '{:08b}'.format(1)
'00000001'

Voir: Mini-langage de spécification de format


Remarque pour Python 2.6 ou version antérieure, vous ne pouvez pas omettre l'identificateur d'argument de position auparavant :, utilisez donc

>>> '{0:08b}'.format(1)
'00000001'      

3
Il n'est pas nécessaire d'utiliser str.format()ici quand format()fera l'affaire. Il vous manque le 0bpréfixe.
Martijn Pieters

2
@MartijnPieters, str.formatest plus flexible que format()parce qu'il vous permettra de faire plusieurs variables à la fois. J'oublie toujours que la formatfonction existe même. Certes, c'est parfaitement adéquat dans ce cas.
Mark Ransom

1
@MarkRansom: Exactement, lorsque vous n'utilisez str.format()qu'un seul {}élément, pas d'autre texte, vous n'utilisez pas de modèle de chaîne, vous formatez une valeur . Dans ce cas, utilisez simplement format(). :-)
Martijn Pieters

30

j'utilise

bin(1)[2:].zfill(8)

va imprimer

'00000001'

9

Vous pouvez utiliser le mini-langage de formatage de chaîne:

def binary(num, pre='0b', length=8, spacer=0):
    return '{0}{{:{1}>{2}}}'.format(pre, spacer, length).format(bin(num)[2:])

Démo:

print binary(1)

Production:

'0b00000001'

EDIT: basé sur l'idée de @Martijn Pieters

def binary(num, length=8):
    return format(num, '#0{}b'.format(length + 2))

2
Le même langage de formatage peut être utilisé pour inclure le préfixe à votre place. Utilisez #. Il existe également format(), ce qui vous évite d'avoir à faire un modèle de chaîne complet.
Martijn Pieters

2

Lorsque vous utilisez Python >= 3.6, le moyen le plus simple est d'utiliser des chaînes f avec un formatage de chaîne :

>>> var = 23
>>> f"{var:#010b}"
'0b00010111'

Explication:

  • var la variable à formater
  • : tout après c'est le spécificateur de format
  • #utiliser la forme alternative (ajoute le 0bpréfixe)
  • 0 pad avec des zéros
  • 10pad à une longueur totale de 10 (cela inclut les 2 caractères pour 0b)
  • b utiliser une représentation binaire pour le nombre

Non, ce n'est pas le plus propre, sauf si vous faites plus avec la chaîne qu'un simple espace réservé . Sinon, format(var, "#010b")communique beaucoup mieux l' intention . C'est cependant l'option la plus rapide. Mais vous le savez déjà, d'accord, parce que je couvre déjà tout ce que vous avez publié dans ma réponse.
Martijn Pieters

1

Parfois, vous voulez juste une simple doublure:

binary = ''.join(['{0:08b}'.format(ord(x)) for x in input])

Python 3


1
Notez que le [ ]ne devrait pas être nécessaire - join()accepte une expression de générateur. ''.join('{0:08b}'.format(ord(x)) for x in input)
Christoph Burschka

@ChristophBurschka note que parce qu'elle str.join()doit faire deux passes, une entrée de générateur est d'abord convertie en liste avant de se joindre. Cela pèse un peu sur les performances et il est en fait préférable de passer une compréhension de liste plutôt qu'une expression de générateur. C'est une si elles font exception à la règle.
Martijn Pieters

-1

Vous pouvez utiliser quelque chose comme ça

("{:0%db}"%length).format(num)

2
Veuillez au moins utiliser le bloc de code pour votre extrait de code. Et si vous voulez vraiment que ce soit une bonne réponse, ajoutez également quelques commentaires sur les raisons pour lesquelles cette solution résout la question du PO.
β.εηοιτ.βε

Vous n'avez pas besoin d'utiliser un style de formatage de chaîne différent simplement pour ajouter une largeur variable. Ajoutez simplement un autre espace réservé:"{:0{l}b}".format(num, l=length)
Martijn Pieters

-1

vous pouvez utiliser la méthode de chaîne rjust de la syntaxe python: string.rjust (length, fillchar) fillchar est facultatif

et pour ta question tu peux écrire comme ça

'0b'+ '1'.rjust(8,'0)

donc ce sera '0b00000001'


Il y a une erreur de syntaxe. Mais plus important encore, il ne répond pas du tout à la question, qui consiste à convertir un inten sa représentation binaire textuelle; vous ne commencez même pas par un int.
Thierry Lathuille

-3

Vous pouvez utiliser zfill:

print str(1).zfill(2) 
print str(10).zfill(2) 
print str(100).zfill(2)

imprime:

01
10
100

J'aime cette solution, car elle aide non seulement lors de la sortie du numéro, mais aussi lorsque vous devez l'assigner à une variable ... par exemple - x = str (datetime.date.today (). Month) .zfill (2) sera renvoie x comme «02» pour le mois de février.


1
Le problème avec zfill est qu'il traite la chaîne binaire comme une chaîne et ajoute les zéros avant l'indicateur binaire 'b' ... par exemple, bin(14) donne `` 0b1110 '' et bin(14).zfill(8) donne `` 000b1110 '' et non `` 0b00001110 '' ce qui est souhaité
Shaun
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.