Konwertuj dane binarne na ASCII i odwrotnie

83

Użycie tego kodu do pobrania łańcucha i przekonwertowania go na binarny:

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

to daje:

0b110100001100101011011000110110001101111

Co jeśli umieszczę to na tej stronie (po prawej stronie), otrzymam wiadomość z hellopowrotem. Zastanawiam się, jakiej metody używa. Wiem, że mógłbym podzielić ciąg binarny na 8, a następnie dopasować go do odpowiedniej wartości bin(ord(character))lub w inny sposób. Naprawdę szukam czegoś prostszego.

sbrichards
źródło
1
Czy jest więc twoje pytanie: „czy istnieje bardziej zwięzły sposób na odwrócenie mojego kodu niż oczywisty”?
tripleee
1
related: b2a_binrozszerzenie w Cythonie pozwala na tworzenie ciągów binarnych ( "01") bezpośrednio z bajtów bez tworzenia pośredniej liczby całkowitej Pythona.
jfs

Odpowiedzi:

160

Dla znaków ASCII w zakresie [ -~]w Pythonie 2:

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

W odwrotnej kolejności:

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

W Pythonie 3.2+:

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

W odwrotnej kolejności:

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

Aby obsługiwać wszystkie znaki Unicode w Pythonie 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'

Oto wersja zgodna z Python 2/3 z jednego źródła:

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

Przykład

>>> text_to_bits('hello')
'0110100001100101011011000110110001101111'
>>> text_from_bits('110100001100101011011000110110001101111') == u'hello'
True
jfs
źródło
3
@JFSebastian Wypróbowałem tę metodę z aktualną wersją Pythona i wygląda na to, że nie działa. <br/> TypeError: „str” nie obsługuje interfejsu bufora <br/> Czy zaktualizowałbyś swoją odpowiedź
hamza
3
@hamza: Działa na Pythonie 2. W Pythonie 3 należy najpierw przekonwertować str na bajty, np.your_string.encode('ascii', 'strict')
jfs
1
@JFSebasitian: dzięki, jednak gdy spróbowałem tego odwrotnie, funkcja unhexlify zwraca komunikat o błędzie: binascii.Error: Ciąg o nieparzystej długości.
hamza
3
@hamza: dodaj go na początku, '0'jeśli długość ciągu szesnastkowego nie jest parzysta. Dzieje się tak, jeśli pierwszy znak w oryginalnym łańcuchu ma kod ascii mniejszy niż 16, np . '\n'Lub '\t'. Nieparzysta długość nigdy nie występuje w przypadku liter ascii [ -~].
jfs
25

Tylko wbudowanepython

Oto czysta metoda Pythona dla prostych łańcuchów, pozostawiona tutaj dla potomności.

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
źródło
2
chr (int ()) jest tym, czego szukałem!
JqueryToAddNumbers
Dokładnie to, czego szukałem !!
Joachim
10

Nie jestem pewien, jak myślisz, jak możesz to zrobić inaczej niż znak po znaku - jest to z natury operacja znak po znaku. Z pewnością istnieje kod umożliwiający wykonanie tego za Ciebie, ale nie ma „prostszego” sposobu niż zrobienie tego znak po znaku.

Najpierw musisz usunąć 0bprefiks i wstawić ciąg od lewej do zera, aby jego długość była podzielna przez 8, aby ułatwić podzielenie łańcucha bitów na znaki:

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

Następnie dzielisz ciąg na bloki po osiem cyfr binarnych, konwertujesz je na znaki ASCII i łączysz z powrotem w ciąg:

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)

Jeśli faktycznie chcesz traktować to jako liczbę, nadal musisz wziąć pod uwagę fakt, że znak znajdujący się najbardziej po lewej stronie będzie miał maksymalnie siedem cyfr, jeśli chcesz przesuwać się od lewej do prawej zamiast od prawej do lewej.

agf
źródło
2

Oto mój sposób na rozwiązanie twojego zadania:

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
źródło
Dlaczego dodajesz „0” w str = „0” + str [2:]? 0b jest potrzebne do usunięcia tutaj, ponieważ się zaczyna.
bimlesh sharma
2

jeśli nie chcesz importować żadnych plików, możesz użyć tego:

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

aby przekonwertować plik tekstowy na binarny.

i możesz użyć tego, aby przekonwertować go z powrotem na ciąg:

StrOrgList = StrOrgMsg.split(" ")


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

Mam nadzieję, że to pomoże, użyłem tego z niestandardowym szyfrowaniem do wysyłania przez TCP.

Kyle Burns
źródło
1

Szukasz odpowiedniego kodu lub zrozumienia algorytmu?

Czy to robi to, czego potrzebujesz ? Konkretnie a2b_uui b2a_uu? Jest tam WIELE innych opcji na wypadek, gdybyś nie był tym, czego chcesz.

(UWAGA: nie jest facetem od Pythona, ale wydawało się to oczywistą odpowiedzią)

Jaxidian
źródło
Trochę to badałem, binascii nie działa dla mnie i głównie szukam kodu, jeśli go widzę, rozumiem. Ale dzięki EDYTUJ: podczas konwersji ascii na binarny za pomocą binascii a2b_uu dla "h" to \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00, co nie jest tym, czego potrzebuję, potrzebuję 'hello' oraz rzeczywistych 1 i 0 nie szelkodowo wyglądający ascii, działa również tylko char przez char
sbrichards
@Jaxidian, który był bardzo pomocny dla moich celów. Ktoś zapisał dane w łańcuchu i mam je. Jestem całkiem pewien, że to 64 binarny b / c wypełnienia. Mogę to z powodzeniem wykorzystać b2a_base64, jednak wynik jest w najlepszym razie zagmatwany. Jak uzyskać listę wartości logicznych / całkowitych (0,1) z tego miejsca?
Ufos
0

Konwertuj plik binarny na jego odpowiednik.

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
źródło
-1

To jest wzmocniona wersja JF Sebastiana. Dzięki za fragmenty, 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
źródło