10

I'm trying to make a simple decoder ring in Python.

Example:

a=b, `b=c, c=d, etc.  

I want the script to take an encoded message and output the decoded message.
For instance, I would input "ifmmp" and it would output "hello".

I've been thinking I need to split all the characters up and loop through them and change their chr() or ord() values.

There doesn't seem to be any documentation for this in python.

Raniz
  • 10,882
  • 1
  • 32
  • 64
user1063543
  • 103
  • 1
  • 1
  • 4
  • 4
    What documentation exactly do you think is missing? `for` loops are documented as are `chr()` and `ord()`. Remember that strings are immutable so you cannot just change one string into another, you have to create a new completely string with the new value. Also unless this is homework on how to do a simple for loop you probably want to forget loops entirely and just call `string.translate()`. – Duncan Nov 24 '11 at 09:22

4 Answers4

14

How about:

s = 'ifmmp'
new_s = ''
for c in s:
    n = ord(c)
    n = n - 1
    if n < ord('a'):
        # 'a' -> 'z'
        n = ord('z')
    new_s += chr(n)
# print('new_s = %r' % new_s)  -> new_s = 'hello'

Of course, this is only handling small letters, not capital.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Sorry, but this solution has some deficiencies. A minor one is that the function must obtain ord('a') for each character c in s: replacing with number 97 would be better. A bigger one is that ``new_s += chr(n)`` creates a new string for each character of s. If the text is 10000 long, you see the useless work... A major deficiency is that capital letters are treated indeed, as all the characters having an ord() < 97 that is to say digits, capital letters, characters !"#$%'()*+,-./:;<=>?@[\]^_` and \t \r \n and others... More in the edit of my answer – eyquem Nov 24 '11 at 11:36
  • @eyquem [Magic numbers](https://en.wikipedia.org/wiki/Magic_number_(programming)) are never a solution I would recommend. – Some programmer dude Feb 03 '17 at 06:32
4

Forget loops, whenever possible use the features built in to Python:

from string import maketrans, translate, ascii_lowercase
import functools
translation = maketrans(ascii_lowercase, ascii_lowercase[-1]+ascii_lowercase[:-1])
decipher = functools.partial(string.translate, table=translation)

print(decipher("ifmmp")) # 'hello'
Duncan
  • 92,073
  • 11
  • 122
  • 156
  • For the record, `maketrans` is a static function of `bytes` and `bytearrays` in Python 3 http://stackoverflow.com/questions/3031045/how-come-string-maketrans-does-not-work-in-python-3-1 – Wtower Apr 29 '15 at 14:27
3
from string import maketrans

table = maketrans('abcdefghijklmnopqrstuvwxyz/','zabcdefghijklmnopqrstuvwxy ')

for x in ('pdfbo','qipophsbqi','cmvf/nppo/jo/b/sfe/tlz'):
    print x,' -> ',x.translate(table)

result

pdfbo  ->  ocean
qipophsbqi  ->  phonograph
cmvf/nppo/jo/b/sfe/tlz  ->  blue moon in a red sky

.

Edit

I rewrote the algorithm of Joachim (function better()) and I wrote my own solution not using maketrans() ( yop() ) :

s = '{ifmmp}\t\tcmvf-nppo \n SUNNY ~ ajhabh 14568'

def bof(s):
    new_s = ''
    for c in s:
        n = ord(c)
        n = n - 1
        if n < ord('a'):
            # 'a' -> 'z'
            n = ord('z')
        new_s += chr(n)
    return new_s


def better(s):
    li = []
    for c in s:
        n = ord(c)-1
        if n == 96:
            li.append('z')
        elif 96<n<122:
            li.append(chr(n))
        else:
            li.append(c)
    return ''.join(li)

def yop(s):
    gen = ((c,ord(c)-1) for c in s)
    return ''.join('z' if y==96 else chr(y) if 96<y<122 else x for x,y in gen)


def better_yop(s):
    def gen(h):
        for c in h:
            n = ord(c)-1
            if n == 96:
                yield 'z'
            elif 96<n<122:
                yield chr(n)
            else:
                yield c
    return ''.join(gen(s))

for truc in (s,bof(s),better(s),yop(s),better_yop(s)):
    print '%r\n%s\n' % (truc,truc)

result

'{ifmmp}\t\tcmvf-nppo \n SUNNY ~ ajhabh 14568'
{ifmmp}     cmvf-nppo 
 SUNNY ~ ajhabh 14568

'zhello|zzbluezmoonzzzzzzzzz}zzigzagzzzzzz'
zhello|zzbluezmoonzzzzzzzzz}zzigzagzzzzzz

'{hello}\t\tblue-moon \n SUNNY ~ zigzag 14568'
{hello}     blue-moon 
 SUNNY ~ zigzag 14568

'{hello}\t\tblue-moon \n SUNNY ~ zigzag 14568'
{hello}     blue-moon 
 SUNNY ~ zigzag 14568

'{hello}\t\tblue-moon \n SUNNY ~ zigzag 14568'
{hello}     blue-moon 
 SUNNY ~ zigzag 14568

However , my function yop() is slower than the function better()

.

Edit

Now the function better_yop() has a speed equivalent to the speed of better()
However, better() seems to be slightly faster than better_yop(). Since it is also simpler, better() is the best

eyquem
  • 26,771
  • 7
  • 38
  • 46
1

I would recommend making the decoder ring a dictionary. Then open the input file for reading, read the file, loop through a character at a time and use the dictionary to translate to an output string. Finally write that string to a file.

ncmathsadist
  • 4,684
  • 3
  • 29
  • 45
  • Yes, I ended up using the maketrans solution, but made a translation table for all 26 orders it could be in, then had the program check for outputted english words, and had the english words written to a file. – user1063543 Nov 27 '11 at 11:42