0

I'm trying to get a string, jJ, as input and then converting each character to it's 6 bit binary form using the mapping given in a and concatenating them and returning it in mapFirst(string). That is, jJ becomes 100011001001.

In binaryToLetter(string) I'm taking the returned value and separating it into parts of 8 bits and converting it back to it's character form and concatenated. 100011001001 becomes 00001000 and 11001001, which are then converted and joined to give (backspace)É.

In my code, I'm getting the error :

Exception has occurred: ValueError
invalid literal for int() with base 2: ''

  File "C:\Users\Sembian\Desktop\exc files new\Ex_Files_Learning_Python\Exercise Files\task_cs\task1.py", line 11, in <genexpr>
    return ''.join( str( int( (binNew[newLen:newLen-i]),2 ) ).replace('0b','').zfill(8) for i in range(0, newLen, n) )

The code I used is :

from textwrap import wrap
a = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/']

def mapFirst(string):
   return ''.join(str(bin(ord(chr(a.index(c))))).replace('0b','').zfill(6) for c in string)

def binaryToLetter(binNew):
   newLen = len(str(binNew))          
   n=8
   return ''.join( str( int( (binNew[newLen:newLen-i]),2 ) ).replace('0b','').zfill(8) for i in range(0, newLen, n) )

def main():
   k = 'jJ'
   print("the first binary value is: ",mapFirst(k))
   print("the final decoded value is: ", binaryToLetter(mapFirst(k)))

if __name__ == "__main__":
  main()
  • probably passing an empty string, that's all. But there's too much code here. Reduce this to a [mcve] this is horrible `''.join(str(bin(ord(chr(a.index(c))))).replace('0b','').zfill(6)` – Jean-François Fabre May 13 '19 at 19:13
  • I'll work on reducing the code, thanks! I checked binNew and it wasn't empty. Which part are you saying might be passing an empty string? – Sembian Balakrishnan May 13 '19 at 19:22
  • 1
    this slicing produces an empty string everytime: `return ''.join( str( int( (binNew[newLen:newLen-i]),2 ) ).replace('0b','').zfill(8) for i in range(0, newLen, n) )` because start of slice is >= end of slice – Jean-François Fabre May 13 '19 at 19:25
  • `range(0, newLen, n)` yields `[0, 8]`. Is this what you wanted? – John Gordon May 13 '19 at 19:27
  • I made start of slice >= end of slice because I wanted it to begin slicing from the right end (since I may have to add '0's in front of the string to make it a multiple of exactly 8 bits). Since this gives an empty string, is there another way to do this? I'm new to python so excuse my mistakes, thanks! – Sembian Balakrishnan May 13 '19 at 19:37
  • To illustrate what they're saying type this in the interpreter: int('',2) – Kenny Ostrom May 13 '19 at 19:45
  • This may be what you want: https://stackoverflow.com/questions/9475241/split-string-every-nth-character – Kenny Ostrom May 13 '19 at 19:46
  • I made `binNew[newLen:newLen-i]` as `binNew[newLen-i:newLen]` to make start of slice < end of slice but i'm still getting the same error. – Sembian Balakrishnan May 13 '19 at 20:07

1 Answers1

0

I managed to get something kinda working. For the first part:

def mapFirst(string):
   return ''.join(bin(a.index(c))[2:].zfill(6) for c in string)

I have removed a bunch of unnecessary clutter:

  1. ord(chr(x)) == x (assuming x:int < 256), because ord is an inverse of chr.
  2. str(bin(x)) == bin(x), because bin already returns a string.
  3. bin(x).replace('0b', '') == bin(x)[2:], because bin will always return a string starting with 0b, so you can use string (list) slicing.

For the second part:

def binaryToLetter(binNew):
   return ''.join(reversed([chr(int(binNew[max(0, i - 8):i], 2))
                            for i in range(len(binNew), 0, -8)]))

To break it down a little:

  1. I am using range(len(binNew), -1, -8) to generate decreasing a sequence from len(binNew) to 0 (inclusive) in steps of -8.
  2. I am then using the list slicing again to get the 8-bit long chunks from binNew, making sure that I don't overshoot the last one (that what the max() is for).
  3. I am turning these 8 char strings to a number with int(..., 2) and turning that number to chr.
  4. Because I am "chopping" away the 8 long substrings starting from the back, I need to reverse the order. But reversed doesn't accept generators, so I change the original generator into a list.
Faboor
  • 1,365
  • 2
  • 10
  • 23
  • It's working for some inputs like `jJ` or even `jJy23ujlmjdkfnjflnjrkfk4j` but not for `Y3Jvc3MgYm90aCB0YWJsZXMgc2l4IHRoaXJ0eSBwcm9ncmFtIGFuYWx5c2lzIGluc2VydCAyMTAxMjM0` which is what I have to decode. I'm getting the same error: ValueError invalid literal for int() with base 2: '' in this case. I tried giving a few more random inputs, and it works in some cases and not in others. I can't figure out why. – Sembian Balakrishnan May 13 '19 at 20:42
  • @SembianBalakrishnan my bad, the range should be `range(len(binNew), 0, -8)`. Edited. The reason why it doesn't work, is that if it perfectly aligned with 8 bit length (ei the original string was multiple of 4 long) it then did a slice [0:0] which will be `""` and that would cause `int` to fail. – Faboor May 13 '19 at 20:45
  • @SembianBalakrishnan but you should be doing `base64.b64decode()` anyway :D – Faboor May 13 '19 at 20:49