Converter em binário e manter zeros à esquerda em Python

154

Estou tentando converter um número inteiro para binário usando a função bin () em Python. No entanto, ele sempre remove os zeros à esquerda, o que eu realmente preciso, de modo que o resultado seja sempre de 8 bits:

Exemplo:

bin(1) -> 0b1

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

Existe alguma forma de fazer isso?

Niels Sønderbæk
fonte
Veja também: Python int para binário? , especialmente minha resposta com a representação de n bits. Não é exatamente o mesmo, mas eu vim a esta pergunta procurando a minha resposta ...
Martin Thoma

Respostas:

219

Use a format()função :

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

A format()função simplesmente formata a entrada seguindo o mini idioma de especificação de formato . A #faz com que o formato incluem o 0bprefixo, e o 010tamanho formata a saída para se ajustar em 10 caracteres largura, com 0enchimento; 2 caracteres para o 0bprefixo, os outros 8 para os dígitos binários.

Esta é a opção mais compacta e direta.

Se você estiver colocando o resultado em uma string maior, use uma literal de string formatada (3.6+) ou use str.format()e coloque o segundo argumento para a format()função após os dois pontos do espaço reservado {:..}:

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

Por acaso, mesmo para formatar apenas um único valor (portanto, sem colocar o resultado em uma string maior), o uso de uma literal de string formatada é mais rápido do que usar 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

Mas eu usaria isso apenas se o desempenho em um loop apertado for importante, pois format(...)comunica melhor a intenção.

Se você não quis o 0bprefixo, simplesmente solte #e ajuste o comprimento do campo:

>>> format(14, '08b')
'00001110'
Martijn Pieters
fonte
3
Exatamente o que eu estava procurando, essa formatação é realmente útil para mim. Comecei a aprender a manipulação de bits e estava pesquisando a formatação de bits para números em Python. Encontrei isso. Obrigado.
kratostoical
Works nice. Pode ficar um pouco volumoso embora. format(192,'08b')+'.'+format(0,'08b')+'.'+format(2,'08b')+'.'+format(33,'08b') 11000000.00000000.00000010.00100001
vozes
@ tjt263: É por isso que afirmo explicitamente que, se você estiver colocando o resultado em uma sequência maior, use uma literal formatada (3.6+) ou use str.format()e coloque o segundo argumento para a função format () após os dois pontos do espaço reservado {:..}:
Martijn Pieters
1
@ tjt263: por exemplo, use f"{192:08b}.{0:08b}.{2:08b}.{33:08b}".
Martijn Pieters
Muito agradável. Eu nunca saberia que é isso que você quis dizer com explicação sozinha. Mas agora que vi seu exemplo, provavelmente nunca esquecerei. Felicidades.
vozes
115
>>> '{:08b}'.format(1)
'00000001'

Consulte: Mini-idioma de especificação de formato


Observe que, para o Python 2.6 ou mais antigo, você não pode omitir o identificador de argumento posicional antes :, portanto, use

>>> '{0:08b}'.format(1)
'00000001'      
bwbrowning
fonte
3
Não há necessidade de usar str.format()aqui quando o format()fará. Está faltando o 0bprefixo.
Martijn Pieters
2
@MartijnPieters, str.formaté mais flexível do que format()porque permitirá que você faça várias variáveis ​​ao mesmo tempo. Eu continuo esquecendo que a formatfunção existe. É certo que é perfeitamente adequado neste caso.
Mark Ransom
1
@MarkRansom: Exatamente, quando você estiver usando apenas str.format()com apenas um {}elemento, nenhum outro texto, você está não usando templates string, você está formatando um valor . Nesse caso, basta usar format(). :-)
Martijn Pieters
30

estou usando

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

irá imprimir

'00000001'
rekinyz
fonte
9

Você pode usar o mini idioma de formatação de string:

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

Demo:

print binary(1)

Resultado:

'0b00000001'

EDIT: baseado na ideia de @Martijn Pieters

def binary(num, length=8):
    return format(num, '#0{}b'.format(length + 2))
Peter Varo
fonte
2
A mesma linguagem de formatação pode ser usada para incluir o prefixo para você. Use #. Também existe format(), o que evita que você precise criar um modelo de string completo.
Martijn Pieters
2

Ao usar Python >= 3.6, a maneira mais limpa é usar f-strings com formatação de string :

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

Explicação:

  • var a variável para formatar
  • : tudo depois disso é o especificador de formato
  • #use o formulário alternativo (adiciona o 0bprefixo)
  • 0 almofada com zeros
  • 10pad a um comprimento total de 10 (inclui os 2 caracteres para 0b)
  • b use representação binária para o número
ruohola
fonte
Não, não é o mais limpo, a menos que você faça mais com a string do que apenas um espaço reservado . Caso contrário, format(var, "#010b")comunica a intenção muito melhor. É, no entanto, a opção mais rápida. Mas você já sabe disso, certo, porque eu já abordo tudo o que você postou na minha resposta.
Martijn Pieters
1

Às vezes, você só quer um liner simples:

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

Python 3

Marca
fonte
1
Observe que isso [ ]não deve ser necessário - join()aceita uma expressão geradora. ''.join('{0:08b}'.format(ord(x)) for x in input)
Christoph Burschka
@ChristophBurschka observe que, como str.join()precisa fazer duas passagens, uma entrada do gerador é primeiro convertida em uma lista antes de ingressar. Isso exige um pouco de desempenho e é melhor aqui passar uma compreensão da lista do que uma expressão geradora. É uma se as exceções à regra.
Martijn Pieters
-1

Você pode usar algo como isto

("{:0%db}"%length).format(num)
Adão
fonte
2
Pelo menos, use o bloco de código para seu snippet de código. E se você realmente deseja que seja uma boa resposta, adicione alguns comentários sobre por que essa solução está resolvendo a questão do OP.
β.εηοιτ.βε
Você não precisa usar um estilo de formatação de string diferente apenas para adicionar uma largura variável. Basta adicionar outro espaço reservado:"{:0{l}b}".format(num, l=length)
Martijn Pieters
-1

você pode usar o método rjust string da sintaxe python: string.rjust (length, fillchar) fillchar é opcional

e para sua pergunta você escreve assim

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

então será '0b00000001'

Jaydeep Mahajan
fonte
Há um erro de sintaxe. Mais importante, porém, não responde à pergunta, que consiste em converter um intem sua representação binária textual; você nem começa com um int.
Thierry Lathuille
-3

Você pode usar o zfill:

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

impressões:

01
10
100

Eu gosto dessa solução, pois ajuda não apenas na saída do número, mas quando você precisa atribuí-lo a uma variável ... por exemplo, - x = str (datetime.date.today (). Month) .zfill (2) retorne x como '02' para o mês de fevereiro.

Anshul Garg
fonte
1
problema com o zfill é que trata a string binária como uma string e adiciona os zeros antes do indicador b 'b' ... por exemplo, bin(14) dá `` 0b1110 '' e bin(14).zfill(8) dá `` 000b1110 '' não `` 0b00001110 '', o que é desejado
Shaun