Convertir cadena a binario en Python

106

Necesito una forma de obtener la representación binaria de una cadena en Python. p.ej

st = "hello world"
toBinary(st)

¿Existe un módulo de alguna manera ordenada de hacer esto?

usuario1090614
fuente
8
¿Cuál espera que sea la salida, específicamente?
NPE
Por "binario", ¿se refiere al tipo 0101010 o al ordnúmero inal de cada carácter en (por ejemplo, hexadecimal)?
2013
Suponiendo que realmente te refieres a binarios (ceros y unos), ¿quieres una representación binaria de cada carácter (8 bits por carácter), uno tras otro? por ejemplo, h es el valor ASCII 104 sería 01101000 en binario
ChrisProsser
Esta pregunta ha sido respondida muchas veces en stackoverflow: stackoverflow.com/questions/11599226/… stackoverflow.com/questions/8553310/…
0xcaff

Respuestas:

124

¿Algo como esto?

>>> st = "hello world"
>>> ' '.join(format(ord(x), 'b') for x in st)
'1101000 1100101 1101100 1101100 1101111 100000 1110111 1101111 1110010 1101100 1100100'

#using `bytearray`
>>> ' '.join(format(x, 'b') for x in bytearray(st, 'utf-8'))
'1101000 1100101 1101100 1101100 1101111 100000 1110111 1101111 1110010 1101100 1100100'
Ashwini Chaudhary
fuente
21
O si desea que cada número binario sea de 1 byte: '' .join (format (ord (i), 'b'). Zfill (8) for i in st)
ChrisProsser
5
Para bytes completos también puede usar ' '.join('{0:08b}'.format(ord(x), 'b') for x in st), que es aproximadamente un 35% más rápido que la zfill(8)solución (al menos en mi máquina).
máximo
¿Qué pasa con la conversión de caracteres de más de un byte, como β, por ejemplo, lo que me parece representado 11001110 10110010internamente por ?
Sergey Bushmanov
1
Sé que esto se publicó hace mucho tiempo, pero ¿qué pasa con los caracteres no ASCII?
pkqxdd
48

Como una forma más pitónica, primero puede convertir su cadena en una matriz de bytes y luego usar la binfunción dentro map:

>>> st = "hello world"
>>> map(bin,bytearray(st))
['0b1101000', '0b1100101', '0b1101100', '0b1101100', '0b1101111', '0b100000', '0b1110111', '0b1101111', '0b1110010', '0b1101100', '0b1100100']

O puedes unirte:

>>> ' '.join(map(bin,bytearray(st)))
'0b1101000 0b1100101 0b1101100 0b1101100 0b1101111 0b100000 0b1110111 0b1101111 0b1110010 0b1101100 0b1100100'

Tenga en cuenta que en python3 debe especificar una codificación para la bytearrayfunción:

>>> ' '.join(map(bin,bytearray(st,'utf8')))
'0b1101000 0b1100101 0b1101100 0b1101100 0b1101111 0b100000 0b1110111 0b1101111 0b1110010 0b1101100 0b1100100'

También puede usar el binasciimódulo en python 2:

>>> import binascii
>>> bin(int(binascii.hexlify(st),16))
'0b110100001100101011011000110110001101111001000000111011101101111011100100110110001100100'

hexlifydevuelva la representación hexadecimal de los datos binarios, luego puede convertir a int especificando 16 como base y luego convertirlo a binario con bin.

Kasravnd
fuente
5
No solo esto es más pitónico, sino que es "más" correcto para cadenas no ASCII de varios bytes.
Sergey Bushmanov
Solo tenga en cuenta que (al menos para la versión actual 3.7.4): (1) bytearrayespera una codificación (no solo una cadena) y (2) map(bin, ...)devolverá el mapobjeto. Para el primer punto, utilizo, por ejemplo, bob.encoding ('ascii') `como lo sugiere @Tao. Para el segundo, apunte, usando el joinmétodo, como en los otros ejemplos de @Kasramvd se mostrará el resultado deseado.
Antoine
35

Solo necesitamos codificarlo.

'string'.encode('ascii')
Tao
fuente
Para mí ( v3.7.4), esto devuelve un bytesobjeto (con las representaciones ascii de cada byte, si está disponible), y para mostrar su representación binaria, necesito bin, por ejemplo, con ' '.join(item[2:] for item in map(bin, 'bob'.encode('ascii')))(tenga en cuenta que 0bdebe eliminarse al comienzo de la representación binaria de cada personaje).
Antoine
15

Puede acceder a los valores de código para los caracteres en su cadena usando la ord()función incorporada. Si luego necesita formatear esto en binario, el string.format()método hará el trabajo.

a = "test"
print(' '.join(format(ord(x), 'b') for x in a))

(Gracias a Ashwini Chaudhary por publicar ese fragmento de código).

Si bien el código anterior funciona en Python 3, este asunto se vuelve más complicado si asume cualquier codificación que no sea UTF-8. En Python 2, las cadenas son secuencias de bytes y la codificación ASCII se asume de forma predeterminada. En Python 3, se supone que las cadenas son Unicode, y hay un bytestipo separado que actúa más como una cadena de Python 2. Si desea asumir cualquier codificación que no sea UTF-8, deberá especificar la codificación.

En Python 3, entonces, puede hacer algo como esto:

a = "test"
a_bytes = bytes(a, "ascii")
print(' '.join(["{0:b}".format(x) for x in a_bytes]))

Las diferencias entre la codificación UTF-8 y ascii no serán obvias para cadenas alfanuméricas simples, pero serán importantes si está procesando texto que incluye caracteres que no están en el conjunto de caracteres ascii.

Mark R. Wilkins
fuente
2

En Python versión 3.6 y superior, puede usar f-string para formatear el resultado.

str = "hello world"
print(" ".join(f"{ord(i):08b}" for i in str))

01101000 01100101 01101100 01101100 01101111 00100000 01110111 01101111 01110010 01101100 01100100
  • El lado izquierdo de los dos puntos, ord (i), es el objeto real cuyo valor se formateará e insertará en la salida. El uso de ord () le da el punto de código base 10 para un solo carácter str.

  • El lado derecho de los dos puntos es el especificador de formato. 08 significa ancho 8, 0 rellenado y b funciona como un signo para generar el número resultante en base 2 (binario).

Vlad Bezden
fuente
1

Esta es una actualización de las respuestas existentes que se usaron bytearray()y ya no pueden funcionar de esa manera:

>>> st = "hello world"
>>> map(bin, bytearray(st))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: string argument without an encoding

Porque, como se explica en el enlace anterior, si la fuente es una cadena, también debe proporcionar la codificación :

>>> map(bin, bytearray(st, encoding='utf-8'))
<map object at 0x7f14dfb1ff28>
Billal Begueradj
fuente
0
def method_a(sample_string):
    binary = ' '.join(format(ord(x), 'b') for x in sample_string)

def method_b(sample_string):
    binary = ' '.join(map(bin,bytearray(sample_string,encoding='utf-8')))


if __name__ == '__main__':

    from timeit import timeit

    sample_string = 'Convert this ascii strong to binary.'

    print(
        timeit(f'method_a("{sample_string}")',setup='from __main__ import method_a'),
        timeit(f'method_b("{sample_string}")',setup='from __main__ import method_b')
    )

# 9.564299999998184 2.943955828988692

method_b es sustancialmente más eficiente para convertir a una matriz de bytes porque hace llamadas a funciones de bajo nivel en lugar de transformar manualmente cada carácter en un número entero y luego convertir ese número entero en su valor binario.

Ben
fuente
-1
a = list(input("Enter a string\t: "))
def fun(a):
    c =' '.join(['0'*(8-len(bin(ord(i))[2:]))+(bin(ord(i))[2:]) for i in a])
    return c
print(fun(a))
Barco solo
fuente
1
¿Le gustaría aumentar esta respuesta de solo código ilegible con alguna explicación? Eso ayudaría a combatir la idea errónea de que StackOverflow es un servicio gratuito de escritura de código. En caso de que desee mejorar la legibilidad, pruebe la información proporcionada aquí: stackoverflow.com/editing-help
Yunnosch