-1

I'm trying to convert string to binary and take one's complement, after that display the string again. i have seen a couples of related post such as here and here and i'm follow the official work where have been posted in here, in the below code after run the code its showing error AttributeError: 'bytes' object has no attribute 'encode'. i'm using python 3.6

the below code is :

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)))
your_string='hello'
b=your_string.encode('ascii', 'strict')
text_to_bits(b)

is there a way after convert it to binary to take one's complement of it and display the string again?

david
  • 1

3 Answers3

0

No need to convert your string into unicode (encode). Your functions work very well. Look at the code below:

your_string='hello'
#b=your_string.encode('ascii', 'strict')
b = text_to_bits(your_string)
print(b)
t = text_from_bits(b)
print(t)

Result:

0110100001100101011011000110110001101111
hello
jose_bacoy
  • 12,227
  • 1
  • 20
  • 38
  • thanks sir, i think you are using python 2, in python 3 it's showing TypeError: 'str' object is not callable , so i was trying to solve the problem by convert str to bytes first like your_string.encode('ascii', 'strict') , but showing another error message is AttributeError: 'bytes' object has no attribute 'encode' – david Nov 08 '19 at 15:00
  • I am using 3.6.5 python --version Python 3.6.5 :: Anaconda, Inc. – jose_bacoy Nov 08 '19 at 15:39
  • i'm using 3.6.4 and still not able to run the code give me same error – david Nov 08 '19 at 15:44
0

If supporting ASCII is enough, you can do this:

a="Hello World!"
b="".join(bin(ord(x)^255)[2:] for x in a)
print(b)
c="".join(chr(int(b[x:x+8],2)^255) for x in range(0,len(b),8))
print(c)
101101111001101010010011100100111001000011011111101010001001000010001101100100111001101111011110

Hello World!

since ASCII codes are below 128, someASCII ^ 255 (the one's complement) is always going to be a 8-bit number (the most significant bit gets set). bin() prepends a 0b prefix, that is what the [2:] gets rid of.

If you need it for generic bytes, some padding magic has to be applied, like

b="".join(("0000000"+bin(ord(x))[2:])[-8:] for x in a)
tevemadar
  • 12,389
  • 3
  • 21
  • 49
  • thx sir for good explain. but which version python are you using? i'm trying your code in python 3.6 and showing b="".join(bin(ord(x)^255)[2:] for x in a) TypeError: 'str' object is not callable – david Nov 08 '19 at 15:24
  • @david I was using 3.6.3 in particular. It seems to work fine on Ideone too: https://ideone.com/wqwVPk – tevemadar Nov 08 '19 at 17:25
0

I feel like you could do this easier:

st = "hello world"
my_binary = ' '.join(format(ord(x), 'b') for x in st)
print(my_binary)

original = ''.join(chr(int(X[:8], 2)) for X in my_binary.split())
print(original)

References:

Then just do twos-compliment on the string with something like:

def binary_str_twos(bin_str):
    twos = []
    first_one = True
    # twos compliment
    for char in reversed(bin_str):
        if char == ' ':
            twos.append(char)
        elif char == '1':
            twos.append('1' if first_one else '0')
            if first_one:
                first_one = False
        else:
            twos.append('0' if first_one else '1')

    return ''.join(reversed(twos))

Note that this isn't as efficient as working with binary only.

-- Edit -- Working in 8-bit binary without spaces:

st = "hello world"
my_binary = ''.join(format(ord(x), '08b') for x in st)
print(my_binary)

original = ''.join(chr(int(my_binary[i:i+8], 2)) for i in range(0, len(my_binary), 8))
print(original)
  • good job sir,thanks, just one thing , how i can remove the spaces in between the bits? in the result shown 1101000 1100101 1101100 1101100 1101111 100000 1110111 1101111 1110010 1101100 1100100 ? i want fully series binary such like (11010001100101110110011011001101111100000111011111011111110010 11011001100100 ) – david Nov 08 '19 at 15:28
  • You can either change the logic to use `''.join(...)` instead of `' '.join(...)` or just do `print(''.join(my_binary.split()))`. Though option 1 would be faster in the long run. – Error - Syntactical Remorse Nov 08 '19 at 15:32
  • thx again sir, i follow what you said , i got this output (1101000110010111011001101100110111110000011101111101111111001011011001100100 Ñ) so the word , hello world display! – david Nov 08 '19 at 15:37
  • @david See my update for working without spaces. ( You may want to work with 16 bits instead of 8 (`' '.join(format(ord(x), '016b')` – Error - Syntactical Remorse Nov 08 '19 at 15:42
  • @Error-Syntavtical Remorse , i appreciate your perfect work. thank you sir. – david Nov 08 '19 at 15:49