Convierta binario a ASCII y viceversa

82

Usando este código para tomar una cadena y convertirla en binario:

bin(reduce(lambda x, y: 256*x+y, (ord(c) for c in 'hello'), 0))

esto produce:

0b110100001100101011011000110110001101111

Lo cual, si lo coloco en este sitio (en el sitio de la derecha) recibo mi mensaje de helloregreso. Me pregunto qué método utiliza. Sé que podría unir la cadena de binarios en 8 y luego hacerla coincidir con el valor correspondiente bin(ord(character))o de alguna otra manera. Realmente busco algo más simple.

sbrichards
fuente
1
Entonces, ¿su pregunta es "hay una manera más sucinta de hacer lo inverso de mi código que lo obvio"?
triplicado
1
relacionado: la b2a_binextensión en Cython permite crear cadenas binarias ( "01") directamente desde cadenas de bytes sin crear un entero Python intermedio.
jfs

Respuestas:

158

Para caracteres ASCII en el rango [ -~]en Python 2:

>>> import binascii
>>> bin(int(binascii.hexlify('hello'), 16))
'0b110100001100101011011000110110001101111'

En reversa:

>>> n = int('0b110100001100101011011000110110001101111', 2)
>>> binascii.unhexlify('%x' % n)
'hello'

En Python 3.2+:

>>> bin(int.from_bytes('hello'.encode(), 'big'))
'0b110100001100101011011000110110001101111'

En reversa:

>>> n = int('0b110100001100101011011000110110001101111', 2)
>>> n.to_bytes((n.bit_length() + 7) // 8, 'big').decode()
'hello'

Para admitir todos los caracteres Unicode en Python 3:

def text_to_bits(text, encoding='utf-8', errors='surrogatepass'):
    bits = bin(int.from_bytes(text.encode(encoding, errors), 'big'))[2:]
    return bits.zfill(8 * ((len(bits) + 7) // 8))

def text_from_bits(bits, encoding='utf-8', errors='surrogatepass'):
    n = int(bits, 2)
    return n.to_bytes((n.bit_length() + 7) // 8, 'big').decode(encoding, errors) or '\0'

Aquí está la versión compatible con Python 2/3 de fuente única:

import binascii

def text_to_bits(text, encoding='utf-8', errors='surrogatepass'):
    bits = bin(int(binascii.hexlify(text.encode(encoding, errors)), 16))[2:]
    return bits.zfill(8 * ((len(bits) + 7) // 8))

def text_from_bits(bits, encoding='utf-8', errors='surrogatepass'):
    n = int(bits, 2)
    return int2bytes(n).decode(encoding, errors)

def int2bytes(i):
    hex_string = '%x' % i
    n = len(hex_string)
    return binascii.unhexlify(hex_string.zfill(n + (n & 1)))

Ejemplo

>>> text_to_bits('hello')
'0110100001100101011011000110110001101111'
>>> text_from_bits('110100001100101011011000110110001101111') == u'hello'
True
jfs
fuente
3
@JFSebastian probé este método con la versión actual de Python y parece que no funciona. <br/> TypeError: 'str' no es compatible con la interfaz de búfer <br/> ¿Actualizaría su respuesta
Hamza
3
@hamza: funciona en Python 2. En Python 3, primero debe convertir str en bytes, por ejemplo,your_string.encode('ascii', 'strict')
jfs
1
@JFSebasitian: gracias, sin embargo, cuando lo intenté al revés, la función unhexlify devolvió un mensaje de error: binascii.Error: Cadena de longitud impar.
Hamza
3
@hamza: antepóngalo con '0'si la longitud de la cadena hexadecimal no es par. Ocurre si el primer carácter de la cadena original tiene un código ascii menor que 16, por ejemplo, '\n'o '\t'. La longitud impar nunca ocurre para las letras ascii [ -~].
jfs
22

Solo incorporadopython

Aquí hay un método de Python puro para cadenas simples, dejado aquí para la posteridad.

def string2bits(s=''):
    return [bin(ord(x))[2:].zfill(8) for x in s]

def bits2string(b=None):
    return ''.join([chr(int(x, 2)) for x in b])

s = 'Hello, World!'
b = string2bits(s)
s2 = bits2string(b)

print 'String:'
print s

print '\nList of Bits:'
for x in b:
    print x

print '\nString:'
print s2

String:
Hello, World!

List of Bits:
01001000
01100101
01101100
01101100
01101111
00101100
00100000
01010111
01101111
01110010
01101100
01100100
00100001

String:
Hello, World!
tmthydvnprt
fuente
2
chr (int ()) es lo que estaba buscando!
JqueryToAddNumbers
¡¡Exactamente lo que estaba buscando también !!
Joachim
9

No estoy seguro de cómo crees que puedes hacerlo aparte de carácter por carácter, es inherentemente una operación de carácter por carácter. Ciertamente, existe un código para hacer esto por usted, pero no hay forma más "simple" que hacerlo carácter por carácter.

Primero, debe quitar el 0bprefijo y poner el cero a la izquierda en la cadena para que su longitud sea divisible por 8, para facilitar la división de la cadena de bits en caracteres:

bitstring = bitstring[2:]
bitstring = -len(bitstring) % 8 * '0' + bitstring

Luego, divide la cadena en bloques de ocho dígitos binarios, los convierte en caracteres ASCII y los vuelve a unir en una cadena:

string_blocks = (bitstring[i:i+8] for i in range(0, len(bitstring), 8))
string = ''.join(chr(int(char, 2)) for char in string_blocks)

Si realmente desea tratarlo como un número, aún debe tener en cuenta el hecho de que el carácter más a la izquierda tendrá como máximo siete dígitos si desea ir de izquierda a derecha en lugar de derecha a izquierda.

agf
fuente
2

Esta es mi forma de resolver tu tarea:

str = "0b110100001100101011011000110110001101111"
str = "0" + str[2:]
message = ""
while str != "":
    i = chr(int(str[:8], 2))
    message = message + i
    str = str[8:]
print message
Minh-Triet Pham Tran
fuente
¿Por qué está agregando '0' en str = "0" + str [2:]?. Se necesita 0b para eliminar aquí porque está comenzando.
bimlesh sharma
2

si no desea importar ningún archivo, puede usar esto:

with open("Test1.txt", "r") as File1:
St = (' '.join(format(ord(x), 'b') for x in File1.read()))
StrList = St.split(" ")

para convertir un archivo de texto a binario.

y puede usar esto para convertirlo de nuevo en cadena:

StrOrgList = StrOrgMsg.split(" ")


for StrValue in StrOrgList:
    if(StrValue != ""):
        StrMsg += chr(int(str(StrValue),2))
print(StrMsg)

Espero que sea útil, lo he usado con un cifrado personalizado para enviar a través de TCP.

Kyle Burns
fuente
1

¿Estás buscando el código para hacerlo o entiendes el algoritmo?

¿Esto hace lo que necesitas ? Específicamente a2b_uuy b2a_uu? Hay MUCHAS otras opciones allí en caso de que no sean las que desea.

(NOTA: No es un tipo Python, pero esta parecía una respuesta obvia)

Jaxidian
fuente
Lo he estado investigando un poco, binascii no me está funcionando, y principalmente busco el código, si puedo verlo, puedo entenderlo. Gracias, aunque EDITAR: al convertir ascii a binario usando binascii a2b_uu para "h" es \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 que no es lo que necesito, necesito 'hola' y 1 y 0 reales no shellcode que parece ascii, también solo funciona char by char
sbrichards
@Jaxidian eso fue muy útil para mis propósitos. Alguien almacenó algunos datos en una cadena y los tengo. Estoy bastante seguro de que es un b / c 64 binario del relleno. Puedo usarlo con éxito b2a_base64en eso, sin embargo, el resultado es, de hecho, confuso en el mejor de los casos. ¿Cómo obtengo una lista de valores booleanos / enteros (0,1) a partir de ahí?
Ovnis
0

Convierte binario en su carácter equivalente.

k=7
dec=0
new=[]
item=[x for x in input("Enter 8bit binary number with , seprator").split(",")]
for i in item:
    for j in i:
        if(j=="1"):
            dec=2**k+dec
            k=k-1
        else:
            k=k-1
    new.append(dec)
    dec=0
    k=7
print(new)
for i in new:
    print(chr(i),end="")
NikhilShri
fuente
-1

Esta es una versión arreglada de JF Sebastian. Gracias por los fragmentos, aunque JF Sebastian.

import binascii, sys
def goodbye():
    sys.exit("\n"+"*"*43+"\n\nGood Bye! Come use again!\n\n"+"*"*43+"")
while __name__=='__main__':
    print "[A]scii to Binary, [B]inary to Ascii, or [E]xit:"
    var1=raw_input('>>> ')
    if var1=='a':
        string=raw_input('String to convert:\n>>> ')
        convert=bin(int(binascii.hexlify(string), 16))
        i=2
        truebin=[]
        while i!=len(convert):
            truebin.append(convert[i])
            i=i+1
        convert=''.join(truebin)
        print '\n'+'*'*84+'\n\n'+convert+'\n\n'+'*'*84+'\n'
    if var1=='b':
        binary=raw_input('Binary to convert:\n>>> ')
        n = int(binary, 2)
        done=binascii.unhexlify('%x' % n)
        print '\n'+'*'*84+'\n\n'+done+'\n\n'+'*'*84+'\n'
    if var1=='e':
        aus=raw_input('Are you sure? (y/n)\n>>> ')
        if aus=='y':
            goodbye()
TH33L1T3
fuente