I'm trying to write a Python program to predict the most likely substitution for a Caesar cipher. I managed to get it working, but it just seems very clunky and slow, especially because I need to preserve cases and non-alphabetical characters.
- Would it be cleaner / more pythonic to use the
chr()
andord()
functions instead of theALPHABET
list? - Any suggestions on how I could improve it overall (while also maintaining relative readability)?
Thank you so much!
ALPHABET = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
FREQUENCIES = [.0817, .0149, .0278, .0425, .1270, .0223, .0202, .0609, .0697, .0015, .0077, .0402, .0241, .0675, .0751, .0193, .0009, .0599, .0633, .0906, .0276, .0098, .0236, .0015, .0197, .0007]
def getGoodness(msg):
msg_length = sum([1 for i in msg if i.isalpha()])
msg_frqs = [round(msg.count(a) / msg_length, 4) for a in ALPHABET]
diffs = [abs(a - b) for a, b in zip(msg_frqs, FREQUENCIES)]
avg_diff = round(sum(diffs) / len(diffs), 4)
return avg_diff
def shift(string, n):
shifted = [i for i in string]
for char in range(len(shifted)):
if shifted[char].isalpha():
new_char = ALPHABET[(ALPHABET.index(shifted[char].lower()) + n) % len(ALPHABET)]
if shifted[char].isupper():
new_char = new_char.upper()
shifted[char] = new_char
return ''.join(shifted)
#########################################
msg = "Oqqcfrwbu hc ozz ybckb zokg ct ojwohwcb, hvsfs wg bc kom o pss gvcizr ps opzs hc tzm. Whg kwbug ofs hcc gaozz hc ush whg toh zwhhzs pcrm ctt hvs ufcibr. Hvs pss, ct qcifgs, tzwsg obmkom psqoigs pssg rcb'h qofs kvoh viaobg hvwby wg wadcggwpzs. Mszzck, pzoqy. Mszzck, pzoqy. Mszzck, pzoqy. Mszzck, pzoqy. Ccv, pzoqy obr mszzck! Zsh'g gvoys wh id o zwhhzs. Poffm! Pfsoytogh wg fsorm!"
goodness = []
shifted = []
for i in range(26):
goodness.append(getGoodness(shift(msg, i)))
shifted.append(shift(msg, i))
gdict = dict(zip(goodness, shifted))
print(gdict.get(min(gdict.keys())))