-1

This is a code written by Alexandre B. on my previous post:

# Your dict
code_2 = {14: 'a', 15: 'b', 16: 'c', 24: 'd', 25: 'e', 26: 'f', 34: 'g',
     35:'h', 36: 'i', 44: 'j', 45: 'k', 46: 'l', 54: 'm', 55: 'n',
     56: 'ñ', 64: 'o', 65: 'p', 66: 'q', 74: 'r', 75: 's', 76: 't',
     84: 'u', 85: 'v', 86: 'w', 94: 'x', 95: 'y', 96: 'z'}

def decode_word(text):
# Check then length or the string
 if len(text) %2 != 0:
    raise ValueError("Text incorrect (must have a even length)")

# Split to a list of 2 numbers
text_l = ["".join([a,b]) for a,b in zip(text[::2], text[1::2])]

# Rebuild the world
word = "".join([code_2.get(int(key), "") for key in text_l])

# Check if all keys have been found
if len(word) < len(text)//2:
    print("WARNING: Some keys doesn't belong to 'code_2'.")
return word

The thing is that, let's say I want to "decrypt" the following: "3525464664 156415" (hello bob) If I put those number in the input it gives an error ("WARNING: Some keys doesn't belong to 'code_2'."). I believe this happens because It doesn't recognize the "space" as a Key on code_2.

Is there a way in which I can decrypt sentences with spaces and all, without getting this error? Probably some of the code or all of it will have to be changed, I don't mind that, I just want this to work.

Thank you on advanced :)

BobEk
  • 21
  • 4

3 Answers3

0

One method is to use a regex match on \d+ and then, for each capture group, "decrypt" it individually. See Python replace string pattern with output of function eg.

This might be in a decode_sentence method which would call decode_word on the individual matches. (Or: choose your own name.)

def decode_sentence(encoded_string):
  # literal almost-verbatim adaptation of the code
  # from the accepted answer in the linked question.. patterns.
  def my_replace(match):
    word = match.group()
    return decode_word(word)

  return re.sub(r'@\d+', my_replace, encoded_string)

Such an approach also allow other punctuation characters and, unlike a split-and-join, it won't "eat" or alter whitespace.

user2864740
  • 60,010
  • 15
  • 145
  • 220
0
def decode_sentence(sentence):
    # Break the sentence into words
    words = sentence.split()
    # Decode words and use join to rebuild the sentence
    return ' '.join([decode_word(word) for word in words])

Pythons str.split() breaks the string up into a list of strings using space as the delimiter. You can then use your decode_word function to decode each word and join them back together with spaces between.

Full example:

# Your dict
code_2 = {14: 'a', 15: 'b', 16: 'c', 24: 'd', 25: 'e', 26: 'f', 34: 'g',
     35:'h', 36: 'i', 44: 'j', 45: 'k', 46: 'l', 54: 'm', 55: 'n',
     56: 'ñ', 64: 'o', 65: 'p', 66: 'q', 74: 'r', 75: 's', 76: 't',
     84: 'u', 85: 'v', 86: 'w', 94: 'x', 95: 'y', 96: 'z'}

def decode_sentence(sentence):
    # Break the sentence into words
    words = sentence.split()
    # Decode words and use join to rebuild the sentence
    return ' '.join([decode_word(word) for word in words])

def decode_word(text):
    # Check then length or the string
    if len(text) %2 != 0:
        raise ValueError("Text incorrect (must have a even length)")

    # Split to a list of 2 numbers
    text_l = ["".join([a,b]) for a,b in zip(text[::2], text[1::2])]

    # Rebuild the world
    word = "".join([code_2.get(int(key), "") for key in text_l])

    # Check if all keys have been found
    if len(word) < len(text)//2:
        print("WARNING: Some keys doesn't belong to 'code_2'.")
    return word

And then you can run:

decode_sentence('1415 1624')

>>>'ab cd'
ScoJo
  • 139
  • 5
  • I don't quite understand, where would this "decode_sentence (sentence)" go in the code.I'm new in programming so there are certain things I find hard to undertand – BobEk Apr 19 '20 at 19:22
  • @BobEk I've updated my answer with a full example including your code – ScoJo Apr 19 '20 at 19:34
0

If you only want to translate the numerical part of the encoding, using a regular expression to capture the digits and just write a function to work on that single word and return the translation. re.sub can then do the substitution. I've also made an encoder as well:

import re

code_2_decode = {14: 'a', 15: 'b', 16: 'c', 24: 'd', 25: 'e', 26: 'f', 34: 'g',
                 35:'h', 36: 'i', 44: 'j', 45: 'k', 46: 'l', 54: 'm', 55: 'n',
                 56: 'ñ', 64: 'o', 65: 'p', 66: 'q', 74: 'r', 75: 's', 76: 't',
                 84: 'u', 85: 'v', 86: 'w', 94: 'x', 95: 'y', 96: 'z'}

# To test encoding, build a code point to replacement map.
# Entries look like {'a':'14', 'b':'16', ...}
code_2_encode = dict({k:f'{v:02d}' for k,v in zip(code_2_decode.values(),code_2_decode.keys())})

# str.translate will map Unicode ordinals to a string.  Build the map it requires.
# Entries look like {97:'14', 98:'15', ...}
# Note: U+0097 is the Unicode ordinal of 'a', U+0098 is the Unicode ordinal of 'b', ...
code_2_xlat = str.maketrans(code_2_encode)

def encode(s):
    return s.translate(code_2_xlat)

def decode(s):

    # replacement function that works on one "word"
    def replace(m):

        word = m.group(0)

        if len(word) % 2:
            raise ValueError('word length must be even')

        # Use a list comprehension to iterate through the "word" string
        # two characters-at-a-time.  Convert the two-character string to
        # an integer and look up the replacement.  finally, join everything
        # together.
        return ''.join([code_2_decode[int(word[i:i+2])]
                        for i in range(0,len(word),2)])

    # Match strings of digits and call the replacement function on string.
    return re.sub(r'\d+',replace,s)

test_string = 'hello bob'
print(encode(test_string))
print(decode(test_string))

test_string = 'hello, world!'
print(encode(test_string))
print(decode(test_string))

Output:

3525464664 156415
hello bob
3525464664, 8664744624!
hello, world!
Mark Tolonen
  • 166,664
  • 26
  • 169
  • 251