Перетворити двійковий формат на ASCII і навпаки


83

Використовуючи цей код, щоб взяти рядок і перетворити його в двійковий:

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

це виводить:

0b110100001100101011011000110110001101111

Що, якщо я розміщу його на цьому сайті (на правому сайті), я отримую своє повідомлення helloназад. Мені цікаво, який метод він використовує. Я знаю, що міг би розділити рядок двійкового файлу на 8, а потім порівняти його з відповідним значенням bin(ord(character))чи іншим способом. Дійсно шукаю щось простіше.


1
Отже, ваше запитання: "чи є більш стислий спосіб зробити зворотний мій код, ніж очевидний"?
триплеє

1
пов'язані: b2a_binрозширення в Cython дозволяє створювати двійкові рядки ( "01") безпосередньо з bytestring без створення проміжного цілого числа 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/> Оновіть свою відповідь
Hamza

3
@hamza: Це працює на Python 2. На Python 3 спочатку потрібно перетворити str у байти, наприклад,your_string.encode('ascii', 'strict')
jfs

1
@JFSebasitian: дякую, однак, коли я спробував це навпаки, функція unhexlify повертає повідомлення про помилку: binascii.Error: рядок непарної довжини.
хамза

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 потрібно видалити тут, тому що він починається.
bimlesh sharma

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, що не те, що мені потрібно, мені потрібні "привіт" та фактичні 1 і 0 не shellcode шукає ascii, також він працює лише char від char
sbrichards

@Jaxidian, що було дуже корисно для моїх цілей. Хтось зберігав деякі дані в рядку, і вони у мене є. Я цілком впевнений, що це 64-бінарний b / c прокладки. Я можу успішно цим скористатись 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 Sebastian's. Дякую за фрагменти, хоча Дж. Ф. Себастьян.

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.