3
\$\begingroup\$

I'm learning Python 3 at the moment, so to test the skills I've learned, I am trying the puzzles at Python Challenge.

I've created some code to solve the 2nd puzzle here. it works, but I think that the way I've done it is very convoluted. Any suggestions on how to solve the puzzle in a simpler way?

(The code basically needs to substitute each letter in a message to the letter 2 spaces to the right of it, such as E->G.)

import string
alphabet = string.ascii_lowercase
letter=0
replaceLetter = 2
times=1
message = input()
newMessage=''
while times < 26:
 newMessage = message.replace(alphabet[letter], str(replaceLetter)+',')
 message = newMessage
 letter = letter + 1
 replaceLetter = replaceLetter + 1
 time = times + 1
 if letter == 26:
 times = 0
 break
newMessage = message.replace('26'+',', 'a')
message = newMessage
newMessage = message.replace('27'+',', 'b')
message = newMessage
number = 25
message = newMessage
while times < 26:
 newMessage = message.replace(str(number)+',', str(alphabet[number]))
 message = newMessage
 letter = letter + 1
 number = number - 1
 time = times + 1
 if number == -1:
 times = 0
 break
print(newMessage)
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Dec 3, 2011 at 3:49
\$\endgroup\$
2
  • \$\begingroup\$ Take a look at the python dictionary. Consider replacing characters? \$\endgroup\$ Commented Dec 3, 2011 at 3:54
  • 1
    \$\begingroup\$ There is a hint in the title of the challenge "What about making trans?". See maketrans. It can be only a couple of lines of code. \$\endgroup\$ Commented Dec 3, 2011 at 6:46

2 Answers 2

3
\$\begingroup\$

I would define a shift function that shifted the letters like so:

from string import whitespace, punctuation
def shift(c, shift_by = 2):
 if c in whitespace + punctuation: return c
 upper_ord, lower_ord, c_ord = ord('A'), ord('a'), ord(c)
 c_rel = (c_ord - lower_ord) if c_ord >= lower_ord else (c_ord - upper_ord)
 offset = lower_ord if c_ord >= lower_ord else upper_ord
 return chr(offset + (c_rel + shift_by) % 26)

Then, to translate a message:

msg = 'a quick brown fox jumped over the lazy dog'
encoded_msg = ''.join(shift(l) for l in msg)

Alternatively, combine Mark Tolonen's maketrans suggestion with g.d.d's deque suggestion to get:

import string
from collections import deque
alphabet = string.ascii_lowercase
alphabet_deque = deque(alphabet)
alphabet_deque.rotate(-2)
rotated_alphabet = ''.join(alphabet_deque)
tbl = string.maketrans(alphabet, rotated_alphabet)

Then, later in the code:

msg = 'a quick brown fox jumped over the lazy dog'
encoded_msg = string.translate(msg, tbl)

This second method only works for lowercase letters, but you can always create two separate translation tables -- one for uppercase letters and another for lowercase letters -- to account for case.

Offtopic note: sometimes I wish Python had Smalltalk-like cascaded message sends. Ah well, one can dream.

answered Dec 7, 2011 at 15:42
\$\endgroup\$
2
\$\begingroup\$

I would do a couple of things differently.

import string
from collections import deque
ascii1 = string.ascii_lowercase
# create a deque to simplify rotation.
d = deque(ascii1)
d.rotate(-2)
ascii2 = ''.join(d)
replacements = dict(zip(ascii1, ascii2))
oldmessage = 'This is a string that we want to run through the cipher.'
newmessage = ''.join(replacements.get(c.lower(), c) for c in oldmessage)
# results in 'vjku ku c uvtkpi vjcv yg ycpv vq twp vjtqwij vjg ekrjgt.'

Note that I didn't do anything here to account for casing.

answered Dec 3, 2011 at 6:13
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.