-3

私は edx 問題セット 5 を実行していますが、コードで問題に遭遇しました。

# 6.00x Problem Set 5
#
# Part 1 - HAIL CAESAR!

import string
import random

WORDLIST_FILENAME = "words.txt"

# -----------------------------------
# Helper code
# (you don't need to understand this helper code)
def loadWords():
    """
    Returns a list of valid words. Words are strings of lowercase letters.

    Depending on the size of the word list, this function may
    take a while to finish.
    """
    print "Loading word list from file..."
    inFile = open(WORDLIST_FILENAME, 'r')
    wordList = inFile.read().split()
    print "  ", len(wordList), "words loaded."
    return wordList

def isWord(wordList, word):
    """
    Determines if word is a valid word.

    wordList: list of words in the dictionary.
    word: a possible word.
    returns True if word is in wordList.

    Example:
    >>> isWord(wordList, 'bat') returns
    True
    >>> isWord(wordList, 'asdf') returns
    False
    """
    word = word.lower()
    word = word.strip(" !@#$%^&*()-_+={}[]|\\:;'<>?,./\"")
    return word in wordList

def randomWord(wordList):
    """
    Returns a random word.

    wordList: list of words  
    returns: a word from wordList at random
    """
    return random.choice(wordList)

def randomString(wordList, n):
    """
    Returns a string containing n random words from wordList

    wordList: list of words
    returns: a string of random words separated by spaces.
    """
    return " ".join([randomWord(wordList) for _ in range(n)])

def randomScrambled(wordList, n):
    """
    Generates a test string by generating an n-word random string
    and encrypting it with a sequence of random shifts.

    wordList: list of words
    n: number of random words to generate and scamble
    returns: a scrambled string of n random words

    NOTE:
    This function will ONLY work once you have completed your
    implementation of applyShifts!
    """
    s = randomString(wordList, n) + " "
    shifts = [(i, random.randint(0, 25)) for i in range(len(s)) if s[i-1] == ' ']
    return applyShifts(s, shifts)[:-1]

def getStoryString():
    """
    Returns a story in encrypted text.
    """
    return open("story.txt", "r").read()


# (end of helper code)
# -----------------------------------


#
# Problem 1: Encryption
#
def buildCoder(shift):
    """
    Returns a dict that can apply a Caesar cipher to a letter.
    The cipher is defined by the shift value. Ignores non-letter characters
    like punctuation, numbers and spaces.

    shift: 0 <= int < 26
    returns: dict
    """
    dict={}
    upper = string.ascii_uppercase
    lower = string.ascii_lowercase
    for l in range(len(upper)):
        dict[upper[l]] = upper[(l+shift)%len(upper)]
    for l in range(len(lower)):
        dict[lower[l]] = lower[(l+shift)%len(lower)]
    return dict


def applyCoder(text, coder):
    """
    Applies the coder to the text. Returns the encoded text.

    text: string
    coder: dict with mappings of characters to shifted characters
    returns: text after mapping coder chars to original text
    """
    new_text=''
    for l in text:
        if not(l in string.punctuation or l == ' ' or l in str(range(10))):
           new_text += coder[l]
        else:
           new_text += l            
    return new_text   

def applyShift(text, shift):
    """
    Given a text, returns a new text Caesar shifted by the given shift
    offset. Lower case letters should remain lower case, upper case
    letters should remain upper case, and all other punctuation should
    stay as it is.

    text: string to apply the shift to
    shift: amount to shift the text (0 <= int < 26)
    returns: text after being shifted by specified amount.
    """
    ### TODO.
    ### HINT: This is a wrapper function.
    coder=buildCoder(shift)
    return applyCoder(text,coder)

#
# Problem 2: Decryption
#
def findBestShift(wordList, text):
    """
    Finds a shift key that can decrypt the encoded text.

    text: string
    returns: 0 <= int < 26
    """
    ### TODO
    wordsFound=0
    bestShift=0

    for i in range(26):
        currentMatch=0
        encrypted=applyShift(text,i)
        lista=encrypted.split(' ')
        for w in lista: 
            if isWord(wordList,w):
                currentMatch+=1
        if currentMatch>wordsFound:
                currentMatch=wordsFound
                bestShift=i
    return bestShift

def decryptStory():
    """
    Using the methods you created in this problem set,
    decrypt the story given by the function getStoryString().
    Use the functions getStoryString and loadWords to get the
    raw data you need.

    returns: string - story in plain text
    """
    text = getStoryString()
    bestMatch = findBestShift(loadWords(), text)
    return applyShift(text, bestMatch)

#
# Build data structures used for entire session and run encryption
#

if __name__ == '__main__':
    wordList = loadWords()
    decryptStory()

s = 'Pmttw, ewztl!'
print findBestShift(wordList, s)

print decryptStory()

問題は、プログラムの単一モジュールが復号化ストーリーとは別に機能することです。そのコードの問題は何ですか?

4

1 に答える 1

1

あなたの最初の問題は、applyCoder書かれたとおりに動作しないことです。

buildCoderdict文字のエントリのみを持つ を構築します。しかし、 、 または、 または でapplyCoderはないものはすべて検索しようとします。私はあなたがそこに欲しかったと思います(なぜならです)が、たとえば改行を与えると、それはまだ爆発するでしょう。in string.punctuation== ' 'in str(range(10))string.digitsstr(range(10))'[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]'story.txt

簡単な修正は、チェックするだけですl in string.ascii_uppercase or l in string.ascii_lowercase。しかし、さらに優れた修正方法があります。同じフィルターを逆に表現する複雑な方法を考え出そうとしたり、同じことを繰り返したりする代わりに、試してみてください。

for l in text:
    new_text += coder.get(l, l)

これは、 がマップ内にあるcoder[l]場合lは を返し、そうでない場合はデフォルト値を返しますl


それを修正すると、関数が実行され、何かが正常に出力されます。しかし、それは正しいものを出力しません。なんで?

さて、これを見てください:

if currentMatch>wordsFound:
    currentMatch=wordsFound
    bestShift=i

wordsFoundしたがって、イニシャルの 0よりも適切な一致を見つけるたびに、currentMatch値を破棄してそのままにしておきwordsFoundます。その逆ではありませんよwordsFound = currentMatchね?


これらの問題の両方を修正しました。

$ ln -s /usr/share/dict/words words.txt
$ echo -e "This is a test.\n\nIs it good enough? Let's see.\n" | rot13 > story.txt
$ python caesar.py
Loading word list from file...
   235886 words loaded.
Loading word list from file...
   235886 words loaded.
18
Loading word list from file...
   235886 words loaded.
This is a test. 

Here's some text. Is it enough? Let's see.

つまり、どこかで不必要な反復作業を行っていることは明らかですが、それ以外は機能します。


このような問題に対する答えを得るよりも、このような問題を自分でデバッグする方法を学ぶ方がおそらく重要なので、いくつかの提案があります。

printいくつかの余分なステートメントを追加して問題を見つけました。重要なものはここにあります:

if currentMatch>wordsFound:
    print i, currentMatch, wordsFound
    currentMatch=wordsFound
    bestShift=i

これは 0 から変化しないことがわかりますwordsFound。また、18 の一致があるシフトを見つけた後でも、1 つの一致のシフトが最良として選択されることがわかります。明らかに、何かが間違っています。

しかし、私はそれをどこに置くべきかわかりませんでした。print私はあちこちに十数行を追加しました。これは、単純なコードをデバッグする最も簡単な方法です。

より複雑なコードの場合、出力するものが多すぎる場合は、logging事後に解析できるログ ファイルに (理想的には を使用して) 書き込むことをお勧めします。または、はるかに単純な入力データを使用して、デバッガーやインタラクティブなビジュアライザー (このようなもの) で実行することをお勧めします。

または、機能しない部分が見つかるまで、物事を削除することをお勧めします。たとえば、シフト 18 がシフト 12 よりも優れていることがわかっている場合は、applyShift12 と 18 で呼び出してみて、それぞれが何を返すかを確認します。

これらの手順で答えが得られない場合でも、SO に投稿するためのより良い質問が得られます。

于 2013-05-06T19:24:15.340 に答える