0

Python で vigenere 暗号を作成しようとしていますが、問題があるようです。これが私の暗号化コードです:

def encryption():
    plaintext=input("Please enter the message you wish to encode.")
    #This allows the user to enter the message they wish to encrypt.
    keyword=input("Please enter your keyword, preferably shorter than the plaintext.")
    #This allows the user to enter a keyword.
    encoded=""
    #This creates a string for the user to input the encrypted message to.
    while len(keyword)<len(plaintext):
        #This begins a while loop based on the fact that the length of the keyword is shorter than the length of the plaintext.
        keyword+=keyword
        #This repeats the keyword.
        if len(keyword)>len(plaintext):
            #This sees if the string length of the keyword is now longer than the string length of the plaintext.
            newkey=keyword[:len(plaintext)]
            #This cuts the string length of the keyword
    for c in range(len(plaintext)):
        char=ord(plaintext[c])
        temp=ord(keyword[c])
        newchar=char+temp
        if newchar>ord("Z"):
            newchar-=26
        newnewchar=chr(newchar)
        encoded+=newnewchar
    print(encoded)

問題が見つからないようですが、平文の「hello」とキーワード「hi」を入力すると、次の記号が表示されます: ¶´º»½. for ループでの追加が行き過ぎている可能性があると思います。

4

3 に答える 3

1

ord() 関数を理解する必要があります。chr() は ord() の逆です。

 for i in range(300):
     print(str(i) + ' ' + chr(i))

Unicode 文字を使用しない場合は、アルファベット文字列を使用できます

alphabet = 'abcdefghijklmnopqrstuvwxyz'
for p,k in zip(plaintext,keyword): # you can directly iterate strings
    char = alphabet.index(p)
    temp = alphabet.index(k)
    newchar = char + temp
    if newchar > 25:
        newchar -= 25
    newchar = alphabet[newchar]
于 2014-11-05T09:22:55.523 に答える
0

ord確かに、 ASCII (A は 65) を使用しているのに対し、de Vigenère では最初の位置に A があったため、この追加は行き過ぎです。を差し引くことができますord('A')。このコードは、すべての文字が大文字であることも前提としています。これは、いくつかの Python のライブラリ関数を使用してタスクを実行するバリエーションです。

import string, itertools
def encrypt(text, key='N'):     # default to rot13 (:
    '''Performs a Vigenere cipher of given plaintext and key'''
    result=[]
    key=key.upper()
    for plain,shift in itertools.izip(text,itertools.cycle(key)):
        shiftindex=string.ascii_uppercase.index(shift)
        shiftto=(string.ascii_uppercase[shiftindex:] +
                 string.ascii_uppercase[:shiftindex])
        trans=string.maketrans(string.ascii_letters,
                               shiftto.lower()+shiftto)
        result.append(plain.translate(trans))
    return ''.join(result)

より完全なバリアントは文字のキーのみを消費する可能性がありますが、文字列に文字のみが含まれる場合はこれで問題ありません。私が ASCII 文字に固執した理由は、ロケール固有のアルファベットが意図した順序でなく、大文字と小文字のセットが一致しない可能性があるためです (たとえば、ドイツ語の ß)。キーを一度だけ変換テーブルのリストに変換することも完全に可能です。

于 2014-11-05T11:02:35.097 に答える
0

ここには他にも改善すべき点がたくさんあるので、バグを解決するだけではありません。
演算子の周りにスペースを入れてa=bください。a = b+-

よりも関数パラメーターを使用する方が良いと思いますinput。入力を取得して入力を暗号化するための 2 番目の関数をいつでも使用できます。

def encryption(plaintext, keyword):
    pass  # (do nothing)

補助関数を書いてみましょう。

私、そしてほとんどの人は、通常、対応するコードの上の行にコメントを入れます。Thisまた、毎回書く必要はなく、通常は命令型が好まれます。

whileそれでは、ループを見てみましょう。状態はlen(keyword) < len(plaintext)、内チェックlen(keyword) > len(plaintext)です。それはいつ起こりますか?最後の反復中のみ。したがって、コードをループの外に移動します。
また、 内で行うことは: (正である)ifを必要としません。 さらに、あなたは決して使用しません!if
any_string[:len(any_string) + n] == any_stringnint
newkey

したがって、ループを次のように単純化できます。

# Begin a while loop based on the fact that the length of the keyword is
# shorter than the length of the plaintext.
while len(keyword) < len(plaintext):
    # Repeat the keyword.
    keyword += keyword

# Cut the string length of the keyword
keyword = keyword[:len(plaintext)]

これは次と同等です:

# Do the operation once
txt_len = len(plaintext)
# Get a string just a bit longer than plaintext
# Otherwise we would have issues when plaintext is not a multiple
# of keyword
keyword *= txt_len // len(keyword) + 1
# Chop of the extra part
keyword = keyword[:txt_len]

の場合、両方とも失敗することに注意してくださいlen(keyword) == 0

forループへ: polku が示したように を
使用できますが、今のところ複雑すぎると仮定して . を保持します。アルファベットを使用することもできますが、単純な算術演算でトリックを実行できます: 、コードで:ziprange
alphabet.index(x) == ord(x) - ord('a')

char = ord(plaintext[c]) - ord('a')
temp = ord(keyword[c]) - ord('a')
newchar = char + temp
# Or simply:
newchar = ord(plaintext[c]) + ord(keyword[c]) - 194  # 2 * ord('a')

大文字を無視すれば、安全に代用できます

if newchar > 25:
    newchar -= 25
# With
newchar %= 25

最後に: alphabet[i] == ord(i + ord('a')).

これをすべてまとめると、次のようになります。

def encryption(plaintext, keyword):
    # Do the operation once
    txt_len = len(plaintext)

    # Get a string just a bit longer than plaintext
    # Otherwise we would have issues when plaintext is not a multiple
    # of keyword
    keyword *= txt_len // len(keyword) + 1  # // is floor division
    # Chop of the extra characters (if there are any)
    keyword = keyword[:txt_len]

    # Create a string to store the encrypted message
    encoded = ""

    # Now you should change this to work with capital letters
    for c in range(txt_len):
        # 194 = 2 * ord('a')
        newchar = ord(plaintext[c]) + ord(keyword[c]) - 194
        newchar %= 25
        encoded += chr(newchar + 97)  # 97 = ord('a')

    return encoded


def encrypt_input():
    # This function should use input to get plaintext and keyword
    # Then use encryption with those strings and print the result
    pass
于 2014-11-05T10:16:44.903 に答える