Saltar al contenido

Convierta una cadena binaria en bytearray en Python 3

Solución:

Aquí hay un ejemplo de cómo hacerlo de la primera forma que mencionó Patrick: convierta la cadena de bits en un int y tome 8 bits a la vez. La forma natural de hacerlo genera los bytes en orden inverso. Para volver a poner los bytes en el orden correcto, utilizo la notación de rebanada extendida en el bytearray con un paso de -1: b[::-1].

def bitstring_to_bytes(s):
    v = int(s, 2)
    b = bytearray()
    while v:
        b.append(v & 0xff)
        v >>= 8
    return bytes(b[::-1])

s = "0110100001101001"
print(bitstring_to_bytes(s))

Claramente, la segunda vía de Patrick es más compacta. 🙂

Sin embargo, hay una mejor manera de hacer esto en Python 3: use el método int.to_bytes:

def bitstring_to_bytes(s):
    return int(s, 2).to_bytes((len(s) + 7) // 8, byteorder="big")

Si len(s) es garantizado para ser un múltiplo de 8, entonces el primer argumento de .to_bytes se puede simplificar:

return int(s, 2).to_bytes(len(s) // 8, byteorder="big")

Esto elevará OverflowError si len(s) es no un múltiplo de 8, que puede ser deseable en algunas circunstancias.


Otra opción es utilizar la doble negación para realizar la división del techo. Para enteros a y b, división de piso usando //

n = a // b

da el entero n tal que
n <= a / b P.ej,
47 // 10 da 4, y

-47 // 10 da -5. Entonces

-(-47 // 10) da 5, realizando eficazmente la división del techo.

Así en bitstring_to_bytes nosotros podría hacer:

return int(s, 2).to_bytes(-(-len(s) // 8), byteorder="big")

Sin embargo, no muchas personas están familiarizadas con este lenguaje eficiente y compacto, por lo que generalmente se considera menos legible que

return (s, 2).to_bytes((len(s) + 7) // 8, byteorder="big")

Tiene que convertirlo en un int y tomar 8 bits a la vez, o cortarlo en cadenas de 8 bytes de largo y luego convertir cada uno de ellos en ints. En Python 3, como muestran las respuestas de PM 2Ring y JF Sebastian, el to_bytes() método de int le permite hacer el primer método de manera muy eficiente. Esto no está disponible en Python 2, por lo que para las personas que se quedan con eso, el segundo método puede ser más eficiente. Aquí hay un ejemplo:

>>> s = "0110100001101001"
>>> bytes(int(s[i : i + 8], 2) for i in range(0, len(s), 8))
b'hi'

Para desglosar esto, la declaración de rango comienza en el índice 0 y nos da índices en la cadena de origen, pero avanza 8 índices a la vez. Ya que s tiene 16 caracteres, nos dará dos índices:

>>> list(range(0, 50, 8))
[0, 8, 16, 24, 32, 40, 48]
>>> list(range(0, len(s), 8))
[0, 8]

(Usamos list() aquí para mostrar los valores que se recuperarán del iterador de rango en Python 3.)

Luego podemos construir sobre esto para dividir la cadena tomando partes de 8 caracteres de largo:

>>> [s[i : i + 8] for i in range(0, len(s), 8)]
['01101000', '01101001']

Luego, podemos convertir cada uno de esos en números enteros, base 2:

>>> list(int(s[i : i + 8], 2) for i in range(0, len(s), 8))
[104, 105]

Y finalmente, envolvemos todo en bytes() para obtener la respuesta:

>>> bytes(int(s[i : i + 8], 2) for i in range(0, len(s), 8))
b'hi'

>>> zero_one_string = "0110100001101001"
>>> int(zero_one_string, 2).to_bytes((len(zero_one_string) + 7) // 8, 'big')
b'hi'

Vuelve bytes objeto que es una secuencia inmutable de bytes. Si quieres conseguir un bytearray – una secuencia mutable de bytes – luego simplemente llame bytearray(b'hi').

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *