簡體   English   中英

如何解決 Python 中的凱撒代碼問題

[英]How can I solve a problem with caesar code in Python

我正在嘗試創建一個簡單的 Caesar Code 函數,該函數必須解密輸入中給出的字符串。

明文 = ABCDEFGHIJKLMNOPQRSTU VWXYZ

加密 = DEFGHIJKLMNOPQRSTUVWX YZABC

這是我的 DECIPHER 代碼:

def deciph(s):
    b='abcdefghijklmnopqrstuvwxyz'
    a='defghijklmnopqrstuvwxyzabc'
    for i in s:
        for j in range(len(a)):
            if i==a[j]:
                s=s.replace(i,b[j])
    return s

這段代碼幾乎總是可以正常工作,例如:

deciph('vxq') --> 'sun'

deciph('ohwwhu') --> 'letter'

這個案例的問題是:

deciph('sp')--> 'mm'  #should be 'pm'

deciph('ol')-->'ii'  #should be 'li'

因此,當第一個字母被解密時,就等於第二個字母被加密。

如何修改我的代碼? 錯誤在哪里? 我知道在互聯網上有很多其他方法可以做同樣的練習,但現在我有興趣了解我的代碼的錯誤。

讓我們使用您的deciph('sp')示例。 問題是當你做s=s.replace(i,b[j]) ,你最初用'p'替換's'所有實例,給你s = 'pp' ,然后在第二遍,用'm'替換'p'所有實例,給你s = 'mm' 這可以通過保存一個新的初始變量rv = '' ,然后對每個字母使用rv+=b[j]而不是改變s來糾正。 然后最后,只需返回rv

如前所述,您觀察到的問題是由於無條件地將s的每個字符替換為“清除”字符 - 因為ab由相同的字母組成,並且str.replace(x, y)將所有出現的x替換為y ,一些字符被一次又一次地“破譯”......

正確解決方案的第一步是手動構建一個新字符串,而不是使用str.replace

def decipher(s):    
    result = []
    for char in s:
        for index, crypted in enumerate(a):
            if char == crypted:
                result.append(b[index])
                # no need to go further
                break
        else:
            # The else clause of a for loop is only executed
            # if the for loop runs to the end without being
            # interrupted by a break statement.
            #
            # Here we use it to handle the case of whitespaces 
            # or any other char that's in `s` but not in `a` 

            result.append(c)

    return "".join(result)

現在雖然這會產生預期的結果,但它非常復雜且效率低下。 您所做的基本上是映射- 在這種情況下,將加密字符映射到解密字符 - 所以這里顯而易見的解決方案是使用Python 的主要mapping內置類型dict

CLEAR = 'abcdefghijklmnopqrstuvwxyz'
CRYPT = 'defghijklmnopqrstuvwxyzabc'

DECIPHER_MAP = dict(zip(CRYPT, CLEAR))

def decipher(s):
    ## the 'unrolled' version:
    # result = []
    # for c in s:
    #     result.append(DECIPHER_MAP.get(c, c))
    # return "".join(result)

    # which is even simpler _and_ faster (and uses less memory)
    # using a generator expression.

    return "".join(DECIPHER_MAP.get(c, c) for c in s)

如您所見,該算法簡單得多。 它也更快(字典查找是 0(1) 並且高度優化),並且占用更少的內存(中間result列表不需要)。

在編程中,選擇合適的數據結構是關鍵...

注意:

現在我有興趣了解我的代碼的錯誤。

這是非常值得稱贊的,至少可以說 - 我希望這里的每個人都會這樣做。 現在,您可以使用最簡單和基本的調試技術自己解決一些問題:通過在戰略時刻打印出您的當前狀態來跟蹤代碼執行:

def deciph(s):    
    for i in s:
        print("i : '{}' - s : '{}'".format(i, s))
        for j in range(len(a)):
            if i==a[j]:
                print("i == '{}' - replacing with '{}'".format(i, b[j]))
                s = s.replace(i, b[j])
                print("now s : '{}'".format(s))   
    return s


>>> deciph("pme")
i : 'p' - s : 'pme'
i == 'p' - replacing with 'm'
now s : 'mme'
i : 'm' - s : 'mme'
i == 'm' - replacing with 'j'
now s : 'jje'
i : 'e' - s : 'jje'
i == 'e' - replacing with 'b'
now s : 'jjb'
'jjb'

您可以使用find()方法來查找循環中字符的位置。

def deciph(s):
    b='abcdefghijklmnopqrstuvwxyz'
    a='defghijklmnopqrstuvwxyzabc'
    decrypted = ''
    for i in s:
       pos = a.find(i)
       if pos != -1:
         decrypted += b[pos]
       else:
          pass # Here you can throw an error
          # Or you can directly pass it to the decrypted string
          # since you want spaces and other punctuation to remain
          # decrypted += i
    return decrypted

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM