Chapter 8 暗号解読

session08-01.py
from railfence import *

cipherText = "n aci mreidontoowp mgorw"
for i in range(2, len(cipherText) + 1):
    print(railDecrypt(cipherText, i))
listing08-01.py
def createWordDict(dName):
    myDict = {}
    with open(dName, 'r') as myFile:
        for line in myFile:
            myDict[line[:-1]] = True  # set all values to True
        return myDict
listing08-02.py
def railBreak(cipherText):
    wordDict = createWordDict('wordlist.txt')
    cipherLen = len(cipherText)
    maxGoodSoFar = 0
    bestGuess = "No words found in dictionary"  # default response
    for i in range(2, cipherLen + 1):
        words = railDecrypt(cipherText, i)
        goodCount = 0  # reset for new list
        for w in words:
            if w in wordDict:
                goodCount = goodCount + 1
        if goodCount > maxGoodSoFar:  # if more words in this list
            maxGoodSoFar = goodCount
            bestGuess = " ".join(words)  # join words in list with space
    return bestGuess
session08-02.py
from railfence import *

cipherText = "n aci mreidontoowp mgorw"
print(railBreak(cipherText))
listing08-03.py
def railDecrypt(cipherText, numRails):
    railLen = len(cipherText) // numRails
    solution = ''
    for col in range(railLen):
        for rail in range(numRails):
            nextLetter = col + (rail * railLen)
            solution = solution + cipherText[nextLetter]
    return solution.split()
session08-03.py
def removeMatches(myString, removeString):
    newStr = " "
    for ch in myString:
        if ch not in removeString:
            newStr = newStr + ch
    return newStr


text = 'Are there 25, 26, or 27 non-letters to remove?'
text = text.lower()
text
nonLetters = removeMatches(text, 'abcdefghijklmnopqrstuvwxyz')
print(nonLetters)
text = removeMatches(text, nonLetters)
print(text)
listing08-04.py
def letterFrequency(text):
    text = text.lower()
    nonLetters = removeMatches(text, 'abcdefghijklmnopqrstyvwxyz')
    text = removeMatches(text, nonLetters)
    lCount = {}
    total = len(text)
    for ch in text:  # cont each letter's occurrence
        lCount[ch] = lCount.get(ch, 0) + 1
    for ch in lCount:  # calculate percentages
        lCount[ch] = lCount[ch] / total
    return lCount
session08-04.py
with open('wells.txt', 'r', encoding='utf-8') as wells:
    text = wells.read()
lf = letterFrequency(text)
for letter in 'abcdefghijklmnopqrstuvwxyz':
    print(letter, lf.get(letter))
session08-05.py
xList = [3, 7, 4, 9]
xList.sort(reverse=True)
xList
listing08-05.py
def getFreq(t):
    return t[1]  # return second item in the tuple
session08-06.py
lfList = list(lf.items())
lfList.sort(key=getFreq, reverse=True)
for empty in lfList:  # each entry is a tuple
    print("{0} {1:.3f}".format(empty[0], empty[1]))
listing08-06.py
def maybeAdd(ch, toList):
    if ch in 'abcdefghijklmnnopqrstyvwxyz' and ch not in toList:
        toList.append(ch)
session08-07.py
myList = []
maybeAdd('a', myList)  # a is a letter and not in the list
print(myList)
maybeAdd('-', myList)  # - is not a letter
print(myList)
maybeAdd('b', myList)  # b is a letter and not in the list
print(myList)
maybeAdd('a', myList)  # a is already in the list
print(myList)
listing08-07.py
def neighborCount(text):
    nbDict = {}
    text = text.lower()
    for i in range(len(text) - 1):
        nbList = nbDict.setdefault(text[i], [])
        maybeAdd(text[i + 1], nbList)
        nbList = nbDict.setdefault(text[i + 1], [])
        maybeAdd(text[i], nbList)
    for key in nbDict.keys():  # replace letters list with count
        nbDict[key] = len(nbDict.get(key))
    return nbDict
listing08-08.py
nbList = nbDict.get(text[i])
if nbList == None:
    nbDict[text[i]] = []
    nbList = nbDict[text[i]]
session08-08.py
freqDict = neighborCount(text)
for i in 'ent':
    print(i, freqDict[i])
listing08-09.py
def maybeAdd(ch, toDict):
    if ch in 'abcdefghijklmnopqrstyvwxyz':
        toDict[ch] = toDict.setdefault(ch, 0) + 1


def neighborCount(text):
    nbDict = {}
    text = text.lower()
    for i in range(len(text) - 1):
        nbList = nbDict.setdefault(text[i], {})
        maybeAdd(text[i + 1], nbList)
        nbList = nbDict.setdefault(text[i + 1], {})
        maybeAdd(text[i], nbList)
    return nbDict
session08-09.py
d = neighborCount(text)
print(d['e'])
print(d['n'])
print(d['t'])
{'h': 10434, 'c': 705, 'u': 1712, 'e': 3143, 'i': 4156, 's': 3095, 'a': 3847,
 'o': 3163, 'r': 1884, 'n': 1744, 'l': 586, 'f': 282, 'w': 215, 't': 864, 'y':
 298, 'm': 80, 'p': 194, 'x': 84, 'b': 34, 'g': 29, 'd': 2}
session08-10.py
cipherText = cipherText.replace('l', 'E')
cipherText = cipherText.replace('h', 'A')

cipherText
listing08-10.py
def sortByLen(w):
    return len(w)
session08-11.py
cipherWords = cipherText.split()
cipherWords.sort(key=sortByLen)
cipherWords
session08-12.py
cipherText = cipherText.replace('b', 'N')
cipherText = cipherText.replace('e', 'D')
cipherText = cipherText.replace('k', 'T')
cipherText = cipherText.replace('u', 'H')
cipherText
session08-13.py
import re

re.match('.ADE', 'FADE')
re.match('.ADE', 'FADER')
re.match('.ADE$', 'FADER')
re.match('.ADE$', 'ADE')
re.match('.ADE$', 'FUDE')
listing08-11.py
def checkWord(regex):
    resList = []
    with open('wordlist.txt', 'r') as wordFile:
        for line in wordFile:
            if re.match(regex, line[: -1]):
                resList.append(line[:-1])
    return resList
session08-14.py
checkWord('.o.ning')
checkWord(' [bcjkmpqruvwxyz]o[bcjkmpqruvwxyz]ning')
checkWord('a..i.al')
checkWord('a..i.al$')
['admiral', 'arrival']
checkWord('a [bcjkmpqruvwxyz] [bcjkmpqruvwxyz]i[bcjkmpqruvwxyz]al$')
listing08-12.py
def checkWord(unused, pattern):
    resList = []
    with open('wordlist.txt', 'r') as wordFile:
        rePat = '['+unused+']'
        regex = re.sub('[a-z]', rePat, pattern) + '$'
        regex = regex.lower()
        print('matching', regex)
        for line in wordFile:
            if re.match(regex, line[:-1]):
                resList.append(line[:-1])
    return resList
session08-15.py
checkWord('bcjkmpqruvwxyz', 'WONDEiFmLLq')
checkWord('bcjkmpqruvwxyz', 'AiiInAL')
checkWord('bcjkmpqruvwxyz', 'mNmSmAL')
session08-16.py
cg = re.match('F(..)L(..)', 'FOILED')
cg
cg.group(1)
cg.group(2)
cg = re.match('F(..)L(..)', 'FOOLER')
cg.groups()
listing08-13.py
def findLetters(unused, pattern):
    resList = []
    with open('wordlist.txt', 'r') as wordFile:
        ctLetters = re.findall('[a-z]', pattern)
        print(ctLetters)
        rePat = '(['+unused+'])'
        regex = re.sub('[a-z]', rePat, pattern) + '$'
        regex = regex.lower()
        for line in wordFile:
            myMatch = re.match(regex, line[:-1])
            if myMatch:
                matchingLetters = myMatch.groups()
                matchList = []
                for l in matchingLetters:
                    matchList.append(l.upper())
                resList.append(line[:-1])
                resList.append(list(zip(ctLetters, matchList)))
    return resList
session08-17.py
re.findall('[123]', '1,234')  # find single characters
re.findall('[1234] +', '1,234')  # find multiple characters
re.findall('[A-Z]', 'Hello World')  # find capital letters
session08-18.py
list(zip([1, 2, 3], [4, 5, 6]))
list(zip(['a', 'b', 'c'], ['Z', 'Y', 'X']))
list(zip(['a', 'b', 'c'], ['Z', 'Y', 'X'], [1, 2, 3]))
session08-19.py
findLetters('bcjkmpqruvwxyz', 'AiiInAL')  # i -> r, n -> V
['arrival', [('i', 'R'), ('i', 'R'), ('n', 'V')]]

findLetters('bcjkmpqruvwxyz', 'ALiEADq')  # g -> Y
findLetters('bcjkmpqruvwxyz', 'giEErE')  # g -> B, r -> Z
findLetters('bcjkmpqruvwxyz', 'mNmSmAL')  # m -> U

cipherText = cipherText.replace('i', 'R')
cipherText = cipherText.replace('n', 'V')
cipherText = cipherText.replace('q', 'Y')
cipherText = cipherText.replace('g', 'B')
cipherText = cipherText.replace('r', 'Z')
cipherText = cipherText.replace('m', 'U')
session08-20.py
findLetters('cjkmpqwx', 'wOaaON')  # w ->C?, w ->P?, a -> M
cipherText = cipherText.replace('w', 'C')
cipherText = cipherText.replace('a', 'M')

findLetters('jkpqx', 'dIT')  # no definitive substitution
findLetters('jkpqx', 'AddEARANCE')  # d -> P
ciphertext = cipherText.replace('d', 'P')

findLetters('jkqx', 'xUST')        # x -> J
cipherText = cipherText.replace('x', 'J')