web-dev-qa-db-ja.com

PythonのCaesar暗号関数

Pythonでユーザーからの入力に基づいて文字をシフトし、最後に新しい文字列を最後に作成する単純なCaesar Cipher関数を作成しようとしています。唯一の問題は、最後の暗号テキストは、シフトされたすべての文字を含む文字列全体ではなく、最後にシフトされた文字のみを表示します。

ここに私のコードがあります:

plainText = raw_input("What is your plaintext? ")
shift = int(raw_input("What is your shift? "))

def caesar(plainText, shift): 

    for ch in plainText:
        if ch.isalpha():
            stayInAlphabet = ord(ch) + shift 
            if stayInAlphabet > ord('z'):
                stayInAlphabet -= 26
            finalLetter = chr(stayInAlphabet)
        cipherText = ""
        cipherText += finalLetter

    print "Your ciphertext is: ", cipherText

    return cipherText

caesar(plainText, shift)
15
user1063450

私はこの答えがあなたの質問に本当に答えているわけではないことを理解していますが、とにかく役立つと思います。文字列メソッドでシーザー暗号を実装する別の方法を次に示します。

def caesar(plaintext, shift):
    alphabet = string.ascii_lowercase
    shifted_alphabet = alphabet[shift:] + alphabet[:shift]
    table = string.maketrans(alphabet, shifted_alphabet)
    return plaintext.translate(table)

実際、文字列メソッドはCで実装されているため、このバージョンではパフォーマンスが向上します。これは、私がこれを行うための「Python」の方法と考えるものです。

42
amillerrhodes

移動する必要があるcipherText = "" forループの開始前。ループを通じて毎回リセットしています。

def caesar(plainText, shift): 
  cipherText = ""
  for ch in plainText:
    if ch.isalpha():
      stayInAlphabet = ord(ch) + shift 
      if stayInAlphabet > ord('z'):
        stayInAlphabet -= 26
      finalLetter = chr(stayInAlphabet)
      cipherText += finalLetter
  print "Your ciphertext is: ", cipherText
  return cipherText
16
I82Much

アスキー番号のトリックを使用する:

# See http://ascii.cl/
upper = {ascii:chr(ascii) for ascii in range(65,91)}
lower = {ascii:chr(ascii) for ascii in range(97,123)}
digit = {ascii:chr(ascii) for ascii in range(48,58)}


def ceasar(s, k):
    for c in s:
        o = ord(c)
        # Do not change symbols and digits
        if (o not in upper and o not in lower) or o in digit:
            yield o
        else:
            # If it's in the upper case and
            # that the rotation is within the uppercase
            if o in upper and o + k % 26 in upper:
                yield o + k % 26
            # If it's in the lower case and
            # that the rotation is within the lowercase
            Elif o in lower and o + k % 26 in lower:
                yield o + k % 26
            # Otherwise move back 26 spaces after rotation.
            else: # alphabet.
                yield o + k % 26 -26

x = (''.join(map(chr, ceasar(s, k))))
print (x)
3
alvas

含まれている電池

_while 1:
    phrase = raw_input("Could you please give me a phrase to encrypt?\n")
    if phrase == "" : break
    print "Here it is your phrase, encrypted:"
    print phrase.encode("rot_13")
print "Have a Nice afternoon!"
_

https://docs.python.org/2/library/codecs.html#python-specific-encodings

Python 3アップデート

fine docs say

[今すぐ_rot_13_]コーデックはテキスト変換を提供します:strからstrへのマッピング。 str.encode()(バイト出力のみを生成)ではサポートされていません。

または、言い換えると、encodeモジュールからcodecsをインポートし、それを最初の引数としてエンコードされる文字列と共に使用する必要があります

_from codecs import decode
...
    print(encode(phrase, 'rot13'))
_
3
gboffi

他の人が指摘したように、forループの繰り返しでcipherTextをリセットしていました。 forループの開始前にcipherTextを配置すると、問題が解決します。

さらに、Pythonの標準ライブラリを使用してこの問題を解決する別の方法があります。 Python Standard Libraryは、関数maketrans()と、文字列を操作するメソッドtranslateを定義します。

関数maketrans()は、translateメソッドで使用できる変換テーブルを作成し、ある文字セットを別の文字セットに効率的に変更します。 (Python例による標準ライブラリ)から引用)。

import string

def caesar(plaintext, shift): 

shift %= 26 # Values greater than 26 will wrap around

alphabet_lower = string.ascii_lowercase
alphabet_upper = string.ascii_uppercase

shifted_alphabet_lower = alphabet_lower[shift:] + alphabet_lower[:shift]
shifted_alphabet_upper = alphabet_upper[shift:] + alphabet_upper[:shift]

alphabet = alphabet_lower + alphabet_upper 
shifted_alphabet = shifted_alphabet_lower + shifted_alphabet_upper

table = string.maketrans(alphabet, shifted_alphabet) 

return plaintext.translate(table)
2
Wasif Hyder

問題は、サイクルの繰り返しごとにcipherTextを空の文字列に設定することです。

cipherText = ""

ループの前に移動する必要があります。

2

@ I82muchが言ったように、cipherText = "" forループの外側。関数の先頭に配置します。また、プログラムにはバグがあり、入力として大文字を取得すると暗号化エラーが生成されます。試してください:

    if ch.isalpha(): 
        finalLetter = chr((ord(ch.lower()) - 97 + shift) % 26 + 97)
1
Joel Cornett
_plainText = raw_input("What is your plaintext? ")
shift = int(raw_input("What is your shift? "))

def caesar(plainText, shift): 
    for ch in plainText:
        if ch.isalpha():
            stayInAlphabet = ord(ch) + shift 
            if stayInAlphabet > ord('z'):
                stayInAlphabet -= 26
            finalLetter = chr(stayInAlphabet)
        #####HERE YOU RESET CIPHERTEXT IN EACH ITERATION#####
        cipherText = ""
        cipherText += finalLetter

    print "Your ciphertext is: ", cipherText

    return cipherText

caesar(plainText, shift)
_

If ch.isalpha()のほかに、_finalLetter=ch_を置くことができます。

次の行を削除する必要があります:_cipherText = ""_

乾杯。

1
JDL
>>> def rotate(txt, key):
...   def cipher(i, low=range(97,123), upper=range(65,91)):
...     if i in low or i in upper:
...       s = 65 if i in upper else 97
...       i = (i - s + key) % 26 + s
...     return chr(i)
...   return ''.join([cipher(ord(s)) for s in txt])

# test
>>> rotate('abc', 2)
'cde'
>>> rotate('xyz', 2)
'zab'
>>> rotate('ab', 26)
'ab'
>>> rotate('Hello, World!', 7)
'Olssv, Dvysk!'
1
Aziz Alto
def encrypt():
    plainText = input("What is your plaintext? ")
    shift = int(input("What is your shift? "))
    cipherText = ""
    for ch in plainText:
        if ch.isalpha():
            stayInAlphabet = ord(ch) + shift
        if stayInAlphabet > ord('z'):
            stayInAlphabet -= 26
        finalLetter = chr(stayInAlphabet)
        cipherText += finalLetter

    print ("Your ciphertext is: ", cipherText,"with a shift of",shift)


def decrypte():
    encryption=input("enter in your encrypted code")
    encryption_shift=int(input("enter in your encryption shift"))

    cipherText1 = ""
    for c in encryption:
        if c.isalpha():
            stayInAlphabet1 = ord(c) - encryption_shift
        if stayInAlphabet1 > ord('z'):
            stayInAlphabet1 += 26
        finalLetter1 = chr(stayInAlphabet1)
        cipherText1 += finalLetter1

    print ("Your ciphertext is: ", cipherText1,"with negative shift of",encryption_shift)

from tkinter import *

menu=Tk()
menu.title("menu")
menu.geometry("300x300")
button1= Button(menu,text="encrypt",command=encrypt)
button1.pack()

button2= Button(menu,text="decrypt",command=decrypte)
button2.pack()

button3= Button(menu,text="exit",command=exit)
button3.pack()

menu.mainloop()
1
StudentPie

これは @ amillerrhodesの答え のコードの改良版であり、小文字だけでなく異なるアルファベットでも機能します。

def caesar(text, step, alphabets):

    def shift(alphabet):
        return alphabet[step:] + alphabet[:step]

    shifted_alphabets = Tuple(map(shift, alphabets))
    joined_aphabets = ''.join(alphabets)
    joined_shifted_alphabets = ''.join(shifted_alphabets)
    table = str.maketrans(joined_aphabets, joined_shifted_alphabets)
    return text.translate(table)

使用例:

>>> import string
>>> alphabets = (string.ascii_lowercase, string.ascii_uppercase, string.digits)
>>> caesar('Abc-xyZ.012:789?жñç', step=4, alphabets=alphabets)
'Efg-bcD.456:123?жñç'

参照:
str.maketransのドキュメント
str.translateのドキュメント
stringライブラリのドキュメント

1
Georgy

ここで、より機能的な方法:(Shift iを使用してエンコードし、次に-iを使用してデコードする場合)

def ceasar(story, shift):
  return ''.join([ # concentrate list to string
            (lambda c, is_upper: c.upper() if is_upper else c) # if original char is upper case than convert result to upper case too
                (
                  ("abcdefghijklmnopqrstuvwxyz"*2)[ord(char.lower()) - ord('a') + shift % 26], # rotate char, this is extra easy since Python accepts list indexs below 0
                  char.isupper()
                )
            if char.isalpha() else char # if not in alphabet then don't change it
            for char in story 
        ])
1
Jamesits

シフト入力で関数reverseを使用し、plain_textをシフトに結合して、暗号テキストとして入力してください。

Plain = int(input("enter a number ")) 
Rev = plain[::-1]
Cipher = " ".join(for cipher_text in Rev) 
0
import string
wrd=raw_input("Enter Word").lower()
fwrd=""
for let in wrd:
    fwrd+=string.ascii_lowercase[(string.ascii_lowercase).index(let)+3]
print"Original Word",wrd
print"New Word",fwrd
0
dan

私によると、この答えはあなたにとって便利です:

def casear(a,key):
str=""
if key>26:
    key%=26
for i in range(0,len(a)):
    if a[i].isalpha():
        b=ord(a[i])
        b+=key
        #if b>90:                   #if upper case letter ppear in your string
        #    c=b-90                 #if upper case letter ppear in your string
        #    str+=chr(64+c)         #if upper case letter ppear in your string
        if b>122:
            c=b-122
            str+=chr(96+c)
        else:
            str+=chr(b)
    else:
        str+=a[i]
print str

a=raw_input()
key=int(input())
casear(a,key)

この関数は、指定されたキーに従ってすべての文字を右にシフトします。

0
Rohit-Pandey
from string import ascii_lowercase as alphabet

class CaesarCypher:
    alpha_len = len(alphabet)
    min_guess_rate = 0.2

暗号化と復号化は同じものです。たとえば、シフト10で復号化する場合、シフト26-10で暗号化できることを意味します。この場合、アルファベット全体をシフトする場合、サイクルは同じになります。また、ここでは大文字と非文字を進めました

    def __call__(self, text, offset, encrypt=True):
        if not encrypt:
            offset = self.alpha_len - offset
        result = []
        for letter in text:
            if not letter.isalpha():
                result.append(letter)
                continue
            letter_to_process = letter.lower()
            processed_letter = self._encrypt_letter(letter_to_process, offset)
            if letter.isupper():
                processed_letter = processed_letter.upper()
            result.append(processed_letter)
        return ''.join(result)

ここではすべての暗号化が行われます。

    def _encrypt_letter(self, letter, offset=0):
        position = (alphabet.find(letter) + offset) % self.alpha_len
        return alphabet[position]

この部分は、辞書の頻度からbroot forceとguessを推測するためのものです。

    @staticmethod
    def __how_many_do_i_know(text):
        clean_words = filter(lambda x: x.isalpha(), text.split())
        clean_words = ['\'{}\''.format(x) for x in clean_words]
        cursor = conn.cursor()
        query = 'SELECT COUNT(*) FROM mydictionary WHERE Word IN ({})'.format(",".join(clean_words))
        cursor.execute(query)
        response = cursor.fetchone()[0]
        return response / len(clean_words)

    def guess_encode(self, text):
        options = [self(text, offset, encrypt=False) for offset in range(self.alpha_len)]
        best_option = [self.__how_many_do_i_know(option) for option in options]
        best_key, guess_rate = max(enumerate(best_option), key=lambda x: x[-1])
        guess_text = options[best_key]
        return best_key, guess_rate, guess_text
0
Eugene Yalansky
message = 'The quick brown fox jumped over the lazy dog. 1234567890 !@#$%^&*()_+-'
encrypted = ''.join(chr(ord(char)+3) for char in message)
decrypted = ''.join(chr(ord(char)-3) for char in encrypted)
print(encrypted)
print(decrypted)
# Wkh#txlfn#eurzq#ir{#mxpshg#ryhu#wkh#od}|#grj1#456789:;<3#$C&'(a)-+,b.0
# The quick brown fox jumped over the lazy dog. 1234567890 !@#$%^&*()_+-
0
Ari

Charからintへの変換を覚えておくのが難しいので、これを最適化できます

def decryptCaesar(encrypted, shift):
    minRange = ord('a')
    decrypted = ""
    for char in encrypted:
        decrypted += chr(((ord(char) - minRange + shift) % 26) + minRange)

    return decrypted
0
Michael Luong