Konwertuj ciąg na binarny w Pythonie

106

Potrzebuję sposobu, aby uzyskać binarną reprezentację ciągu w Pythonie. na przykład

st = "hello world"
toBinary(st)

Czy istnieje jakiś zgrabny sposób na zrobienie tego?

user1090614
źródło
8
Jaki będzie konkretnie efekt końcowy?
NPE
Czy przez „binarny” masz na myśli typ 0101010, czy też inal ordnumer każdego znaku (np. Szesnastkowy)?
cdarke
Zakładając, że faktycznie masz na myśli binarne (zera i jedynki), czy chcesz binarną reprezentację każdego znaku (8 bitów na znak) jeden po drugim? np. h to ascii, wartość 104 byłaby binarna jako 01101000
ChrisProsser
Na to pytanie odpowiadano wiele razy na stackoverflow: stackoverflow.com/questions/11599226/… stackoverflow.com/questions/8553310/…
0xcaff

Odpowiedzi:

124

Coś takiego?

>>> 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
źródło
21
Lub jeśli chcesz, aby każda liczba binarna miała 1 bajt: '' .join (format (ord (i), 'b'). Zfill (8) for i in st)
ChrisProsser
5
Do pełnych bajtów można również użyć ' '.join('{0:08b}'.format(ord(x), 'b') for x in st), co jest około 35% szybsze niż zfill(8)rozwiązanie (przynajmniej na moim komputerze).
maks.
A co z konwersją znaków więcej niż jednobajtowych β, na przykład, które wydają mi się reprezentowane przez 11001110 10110010wewnętrznie?
Sergey Bushmanov
1
Wiem, że to zostało opublikowane dawno temu, ale co ze znakami spoza ASCII?
pkqxdd
48

W bardziej Pythonowym sposobie możesz najpierw przekonwertować swój ciąg na tablicę bajtów, a następnie użyć binfunkcji w map:

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

Lub możesz do niego dołączyć:

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

Zauważ, że w python3 musisz określić kodowanie bytearrayfunkcji:

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

Możesz także użyć binasciimodułu w Pythonie 2:

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

hexlifyzwróć szesnastkową reprezentację danych binarnych, a następnie możesz przekonwertować je na int, określając 16 jako podstawę, a następnie przekonwertuj je na binarne za pomocą bin.

Kasravnd
źródło
5
Nie tylko jest to bardziej pythonowe, ale jest „bardziej” poprawne dla wielobajtowych ciągów innych niż ASCII.
Sergey Bushmanov
Wystarczy zauważyć, że (przynajmniej dla bieżącej wersji 3.7.4): (1) bytearrayoczekuje kodowania (nie tylko ciągu znaków), a (2) map(bin, ...)zwróci mapobiekt. W pierwszym punkcie używam na przykład bob.encoding ('ascii') `zgodnie z sugestią @Tao. Po drugie, wskaż, używając joinmetody, tak jak w innych przykładach @Kasramvd wyświetli pożądany wynik.
Antoine
36

Musimy to tylko zakodować.

'string'.encode('ascii')
Tao
źródło
Dla mnie ( v3.7.4) zwraca to bytesobiekt (z reprezentacjami ascii każdego bajtu, jeśli jest dostępny), a żeby wyświetlić jego binarną reprezentację potrzebuję binnp. With ' '.join(item[2:] for item in map(bin, 'bob'.encode('ascii')))(uwaga, którą 0bnależy usunąć na początku reprezentacji binarnej każdego znaku).
Antoine,
15

Możesz uzyskać dostęp do wartości kodu dla znaków w ciągu za pomocą funkcji ord()wbudowanej. Jeśli potem będziesz musiał sformatować to w formacie binarnym, string.format()metoda wykona zadanie.

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

(Podziękowania dla Ashwini Chaudhary za opublikowanie tego fragmentu kodu).

Chociaż powyższy kod działa w Pythonie 3, sprawa staje się bardziej skomplikowana, jeśli zakładasz kodowanie inne niż UTF-8. W Pythonie 2 ciągi są sekwencjami bajtów i domyślnie zakłada się kodowanie ASCII. W Pythonie 3 przyjmuje się, że łańcuchy są kodami Unicode i istnieje oddzielny bytestyp, który działa bardziej jak łańcuch w Pythonie 2. Jeśli chcesz założyć kodowanie inne niż UTF-8, musisz określić kodowanie.

W Pythonie 3 możesz więc zrobić coś takiego:

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

Różnice między kodowaniem UTF-8 i ascii nie będą oczywiste w przypadku prostych ciągów alfanumerycznych, ale staną się ważne, jeśli przetwarzasz tekst zawierający znaki spoza zestawu znaków ascii.

Mark R. Wilkins
źródło
2

W Pythonie w wersji 3.6 i nowszych możesz użyć f-string do sformatowania wyniku.

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

01101000 01100101 01101100 01101100 01101111 00100000 01110111 01101111 01110010 01101100 01100100
  • Lewa strona dwukropka, ord (i), to rzeczywisty obiekt, którego wartość zostanie sformatowana i wstawiona do wyniku. Użycie ord () daje punkt kodowy przy podstawie 10 dla pojedynczego znaku str.

  • Prawa strona dwukropka to specyfikator formatu. 08 oznacza szerokość 8, 0 wypełnione, a b działa jako znak, aby wyprowadzić wynikową liczbę w bazie 2 (binarnie).

Vlad Bezden
źródło
1

To jest aktualizacja istniejących odpowiedzi, które były używane bytearray()i nie mogą już działać w ten sposób:

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

Ponieważ, jak wyjaśniono w powyższym linku, jeśli źródłem jest ciąg, musisz również podać kodowanie :

>>> map(bin, bytearray(st, encoding='utf-8'))
<map object at 0x7f14dfb1ff28>
Billal Begueradj
źródło
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

Metoda method_b jest znacznie bardziej wydajna w konwertowaniu na tablicę bajtów, ponieważ wykonuje wywołania funkcji niskiego poziomu, zamiast ręcznie przekształcać każdy znak na liczbę całkowitą, a następnie konwertować tę liczbę całkowitą na jej wartość binarną.

Ben
źródło
-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))
Statek solo
źródło
1
Czy chciałbyś rozszerzyć tę nieczytelną odpowiedź zawierającą tylko kod o jakieś wyjaśnienie? Pomogłoby to w zwalczaniu błędnego przekonania, że ​​StackOverflow to bezpłatna usługa pisania kodu. Jeśli chcesz poprawić czytelność, wypróbuj informacje podane tutaj: stackoverflow.com/editing-help
Yunnosch