Преобразование двоичного кода в ASCII и наоборот


83

Используя этот код, чтобы взять строку и преобразовать ее в двоичную форму:

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

это выводит:

0b110100001100101011011000110110001101111

Что, если я помещу его на этот сайт (на сайте справа), я получу свое сообщение helloобратно. Мне интересно, какой метод он использует. Я знаю, что могу разделить двоичную строку на 8, а затем сопоставить ее с соответствующим значением bin(ord(character))или каким-либо другим способом. На самом деле ищу что-то попроще.


1
Итак, ваш вопрос: «Есть ли более лаконичный способ сделать инверсию моего кода, чем очевидный»?
tripleee

1
related: b2a_binextension в Cython позволяет создавать двоичные строки ( "01") непосредственно из строк байтов без создания промежуточного целого числа Python.
jfs

Ответы:


160

Для символов ASCII в диапазоне [ -~]на Python 2:

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

Задом наперед:

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

В Python 3.2+:

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

Задом наперед:

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

Для поддержки всех символов Unicode в 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'

Вот версия, совместимая с Python 2/3 с одним исходным кодом:

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

пример

>>> text_to_bits('hello')
'0110100001100101011011000110110001101111'
>>> text_from_bits('110100001100101011011000110110001101111') == u'hello'
True

3
@JFSebastian Я пробовал этот метод с текущей версией Python, и мне кажется, что он не работает. <br/> TypeError: 'str' не поддерживает интерфейс буфера <br/> Не могли бы вы обновить свой ответ
Хамза

3
@hamza: Это работает на Python 2. На Python 3 вам сначала нужно преобразовать str в байты, например,your_string.encode('ascii', 'strict')
jfs

1
@JFSebasitian: спасибо, но когда я попробовал наоборот, функция unhexlify вернула сообщение об ошибке: binascii.Error: Строка нечетной длины.
hamza

3
@hamza: добавьте его, '0'если длина шестнадцатеричной строки не четная. Это происходит, если первый символ в исходной строке имеет код ascii меньше 16, например, '\n'или '\t'. Нечетная длина никогда не бывает для букв ascii [ -~].
jfs

25

Только встроенныйpython

Вот чистый метод Python для простых строк, оставленный здесь для потомков.

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!

2
chr (int ()) - это то, что я искал!
JqueryToAddNumbers

Именно то, что я тоже искал !!
Иоахим

10

Я не уверен, как вы думаете, что вы можете сделать это, кроме посимвольного - это по сути посимвольная операция. Конечно, есть код, чтобы сделать это за вас, но нет более простого способа, чем делать это посимвольно.

Во-первых, вам нужно удалить 0bпрефикс и заполнить строку нулями слева, чтобы ее длина делилась на 8, чтобы упростить разделение строки битов на символы:

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

Затем вы делите строку на блоки из восьми двоичных цифр, конвертируете их в символы ASCII и снова объединяете их в строку:

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)

Если вы действительно хотите рассматривать его как число, вы все равно должны учитывать тот факт, что крайний левый символ будет иметь длину не более семи цифр, если вы хотите идти слева направо, а не справа налево.


2

Это мой способ решить вашу задачу:

str = "0b110100001100101011011000110110001101111"
str = "0" + str[2:]
message = ""
while str != "":
    i = chr(int(str[:8], 2))
    message = message + i
    str = str[8:]
print message

Почему вы добавляете "0" в str = "0" + str [2:]?. 0b необходимо удалить здесь, потому что он начинается.
бимлеш шарма 05

2

если вы не хотите импортировать какие-либо файлы, вы можете использовать это:

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

для преобразования текстового файла в двоичный.

и вы можете использовать это, чтобы преобразовать его обратно в строку:

StrOrgList = StrOrgMsg.split(" ")


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

надеюсь, что это будет полезно, я использовал это с некоторым настраиваемым шифрованием для отправки по TCP.


1

Вы ищете код для этого или разбираетесь в алгоритме?

Это то, что вам нужно ? Конкретно a2b_uuа b2a_uu? Есть МНОГО других вариантов, если они вам не нужны.

(ПРИМЕЧАНИЕ: не парень Python, но это казалось очевидным ответом)


Я немного исследовал это, binascii у меня не работает, и в основном ищу код, если я его вижу, я могу его понять. Спасибо, хотя РЕДАКТИРОВАТЬ: при преобразовании ascii в двоичный с использованием binascii a2b_uu для "h" это \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00, что мне не нужно, мне нужны 'hello' и фактические 1 и 0 не шеллкод, выглядящий как ascii, также он работает только char от char
sbrichards

@Jaxidian, который мне очень помог. Кто-то сохранил данные в строке, и они у меня есть. Я совершенно уверен, что это 64-бинарный б / с заполнения. Я могу успешно использовать b2a_base64это, однако результат действительно в лучшем случае сбивает с толку. Как мне получить оттуда список логических / целых чисел (0,1)?
Ufos

0

Преобразуйте двоичный код в эквивалентный ему символ.

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

-1

Это обновленная версия Дж. Ф. Себастьяна. Спасибо за фрагменты, хотя JF Себастьян.

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()
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.