Text puzzles: ciphers and anagrams
Part of the free LogicWiz Python course, Module 4: Strings. The examples and practice run in the app.
Aarav and Meher pass notes in class that say Nffu bu dbouffo bu 2. Every letter is shifted one step. That's a Caesar cipher, and with ord() and chr() you can write it in eight lines.
You'll learn to
- Turn characters into numbers and back with `ord` and `chr`
- Write a Caesar cipher that wraps Z round to A
- Check whether two words are anagrams
- Count how often each character appears
Learn
Every character is a number
Inside the computer each character is stored as a number (its Unicode code point). ord(ch) gives the number; chr(n) gives the character back.
'A'to'Z'are 65 to 90'a'to'z'are 97 to 122'0'to'9'are 48 to 57
Letters are in a row, so ord('C') - ord('A') is 2: C is letter number 2, counting from 0. Small letters are exactly 32 more than capitals.
ord and chr
print(ord("A"), ord("Z"), ord("a"), ord("0"))
print(chr(66), chr(100))
print(chr(ord("C") + 2))
print(ord("b") - ord("a"))
print(chr(ord("m") - 32))
Shifting with wrap-around
To shift a capital letter by k:
- Position in the alphabet:
pos = ord(ch) - ord('A')(A → 0, Z → 25) - Shift and wrap:
new = (pos + k) % 26. The% 26turns 26 back into 0, so Z + 1 lands on A. It works for negativektoo. - Back to a letter:
chr(new + ord('A'))
For small letters use ord('a') instead.
Shift one letter
def shift(ch, k):
pos = ord(ch) - ord("A")
new = (pos + k) % 26
return chr(new + ord("A"))
print(shift("C", 3))
print(shift("Y", 3))
print(shift("A", -1))
The whole cipher
def caesar(text, k):
out = ""
for ch in text:
if ch.isupper():
out += chr((ord(ch) - 65 + k) % 26 + 65)
elif ch.islower():
out += chr((ord(ch) - 97 + k) % 26 + 97)
else:
out += ch
return out
secret = caesar("Meet at canteen at 2", 1)
print(secret)
print(caesar(secret, -1))
Spaces and digits pass through unchanged. Decoding is just shifting by -k.
Forget the % 26 and 'Z' shifted by 1 becomes chr(91), which is '['. Always go letter → position → shift % 26 → letter.
Anagrams: same letters, new order
def is_anagram(a, b):
a = a.replace(" ", "").lower()
b = b.replace(" ", "").lower()
return sorted(a) == sorted(b)
print(sorted("listen"))
print(is_anagram("Listen", "Silent"))
print(is_anagram("Dormitory", "Dirty room"))
print(is_anagram("chai", "chat"))
sorted(s) gives a list of the characters in order. Two words are anagrams exactly when their sorted letters match.
Character frequency
text = "banana"
seen = ""
for ch in text:
if ch not in seen:
print(ch, text.count(ch))
seen += ch
seen remembers which characters were already reported, so each prints once. In Module 6 a dictionary does this in one pass.
TCS NQT, Infosys and Wipro coding rounds love exactly these: Caesar shifts, anagram checks, the most frequent character, and compressing aaabb to a3b2. They are string loops plus a little ord arithmetic.
In one line
ord turns a character into its code and chr back; shift letters with (pos + k) % 26; anagrams have equal sorted() letters.