Rotate list every for every letter in string
I am attempting to make a Caesar cipher that changes the key each letter, I currently have a working cipher that scrambles the entire string once, running 1-25 however I would like it to do it for each letter, as in the string "ABC" would shift A by 1, B by 2 and C by 3, resulting in BDF
I already have a working cipher, and am just not sure how to have it change each letter.
upper = collections.deque(string.ascii_uppercase) lower = collections.deque(string.ascii_lowercase) upper.rotate(number_to_rotate_by) lower.rotate(number_to_rotate_by) upper = ''.join(list(upper)) lower = ''.join(list(lower)) return rotate_string.translate(str.maketrans(string.ascii_uppercase, upper)).translate(str.maketrans(string.ascii_lowercase, lower)) #print (caesar("This is simple", 2)) our_string = "ABC" for i in range(len(string.ascii_uppercase)): print (i, "|", caesar(our_string, i))
Outcome is this:
0 | ABC 1 | ZAB 2 | YZA 3 | XYZ 4 | WXY 5 | VWX 6 | UVW 7 | TUV 8 | STU 9 | RST 10 | QRS 11 | PQR 12 | OPQ 13 | NOP 14 | MNO 15 | LMN 16 | KLM 17 | JKL 18 | IJK 19 | HIJ 20 | GHI 21 | FGH 22 | EFG 23 | DEF 24 | CDE 25 | BCD
What I would like is to have it a shift of 1 or 0 for the first letter, then 2 for the second, and so on.
Good effort! Note that the mapping doesn't only rearrange letters in the alphabet, so it's never achieved by rotating the alphabet. In your example, upper would become the following mapping:
Also note this cipher is not easily reversible, i.e. it's not clear whether to reverse 'B'->'A' or 'B'->'N'.
When you feel confused about a piece of code, often it's a good sign it's time to refactor a part of it into a separate function, e.g. like this:
import string def letter_index(letter): """Determines the position of the given letter in the English alphabet 'a' -> 0 'A' -> 0 'z' -> 25 """ if letter not in string.ascii_letters: raise ValueError("The argument must be an English letter") if letter in string.ascii_lowercase: return ord(letter) - ord('a') return ord(letter) - ord('A') def caesar(s): """Ciphers the string s by shifting 'A'->'B', 'B'->'D', 'C'->'E', etc The shift is cyclic, i.e. 'A' comes after 'Z'. """ ret = "" for letter in s: index = letter_index(letter) new_index = 2*index + 1 if new_index >= len(string.ascii_lowercase): # The letter is shifted farther than 'Z' new_index %= len(string.ascii_lowercase) new_letter = chr(ord(letter) - index + new_index) ret += new_letter return ret print('caesar("ABC"):', caesar("ABC")) print('caesar("abc"):', caesar("abc")) print('caesar("XYZ"):', caesar("XYZ"))
caesar("ABC"): BDF caesar("abc"): bdf caesar("XYZ"): VXZ