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?

Niels Sønderbæk
la source
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'
Martijn Pieters
la source
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'      
bwbrowning
la source
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'
Rekinyz
la source
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))
Peter Varo
la source
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
rouohola
la source
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

marque
la source
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)
Adam
la source
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'

Jaydeep Mahajan
la source
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.

Anshul Garg
la source
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