Цезарь - python

Помогите решить задачу:

Напишите функцию encrypt_caesar(msg, shift), которая кодирует сообщение шифром Цезаря и возвращает его. Шифр Цезаря заменяет каждую букву в тексте на букву, которая отстоит в алфавите на некоторое фиксированное число позиций. В функцию передается сообщение и сдвиг алфавита. Если сдвиг не указан, то пусть ваша функция кодирует сдвиг алфавита на 3 позиции: А →Г, Б →Д, В →Е, … Э →А, Ю →Б, Я →В Все символы, кроме русских букв должны остаться неизменными. Маленькие буквы должны превращаться в маленькие, большие — в большие. Напишите также функцию декодирования decrypt_caesar(msg, shift), также использующую сдвиг по умолчанию. При написании функции декодирования используйте вашу функцию кодирования.

Код:

alpha = ' abcdefghijklmnopqrstuvwxyz'
n = int(input())
s = input().strip()
res = ''
for c in s:
    res += alpha[(alpha.index(c) + n) % len(alpha)]
print('Result: "' + res + '"')

Ожидаемый результат Зг кзугефхецих фгогх Щикгуя! Да здравствует салат Цезарь!

Вывод Makefile:5: recipe for target 'run' failed


Ответы (3 шт):

Автор решения: Стас

Вы пишете:

Ожидаемый результат Зг кзугефхецих фгогх Щикгуя! Да здравствует салат Цезарь!

но это противоречит условию:

Шифр Цезаря заменяет каждую букву в тексте на букву, которая отстоит в алфавите на некоторое фиксированное число позиций

Смотрите сами: Д -> З - смещение на 4 позиции, а -> г - смещение на 3 позиции, з -> к - 3 позиции, д -> з - 4 позиции. Ну, вы поняли.

Я сделал смещение на фиксированое число позиций.

Вот вариант с рекурсией:

small_symbols = "абвгдеёжзийклмнопрстуфхцчшщъыьэюя"
big_symbols = "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ"


def shift(text, symbols, n):
    index = symbols.find(text)
    if index + n < len(symbols):
        return symbols[index + n]
    else:
        return symbols[(index + n) % len(symbols)]

    

def back_shift(text, symbols, n):
    index = symbols.find(text)
    if index - n >= 0:
        return symbols[index - n]
    else:        
        return symbols[(index - n) % len(symbols)]

    

def encrypt(text, n = 3, i = 0, res = ""):
    if (len(res) == len(text)): return res
    
    if text[i].isupper():
        res += shift(text[i], big_symbols, n)
        
    elif text[i].islower():
        res += shift(text[i], small_symbols, n)
    else:
        res += text[i]
        
    return encrypt(text, n, i+1, res)


def decrypt (text, n = 3, i = 0, res = ""):
    if (len(res) == len(text)): return res
    
    if text[i].isupper():
        res += back_shift(text[i], big_symbols, n)
        
    elif text[i].islower():
        res += back_shift(text[i], small_symbols, n)
    else:
        res += text[i]
        
    return decrypt(text, n, i+1, res)



str = encrypt(input())
print(str)
print(decrypt(str))

И без неё:

small_symbols = "абвгдеёжзийклмнопрстуфхцчшщъыьэюя"
big_symbols = "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ"


def shift(text, symbols, n):
    index = symbols.find(text)
    if index + n < len(symbols):
        return symbols[index + n]
    else:
        return symbols[(index + n) % len(symbols)]

    

def back_shift(text, symbols, n):
    index = symbols.find(text)
    if index - n >= 0:
        return symbols[index - n]
    else:        
        return symbols[(index - n) % len(symbols)]

    

def encrypt(text, n = 3):
    res = ""

    for i in range(0, len(text)): 
        if text[i].isupper():
            res += shift(text[i], big_symbols, n)
        
        elif text[i].islower():
            res += shift(text[i], small_symbols, n)
        else:
            res += text[i]
        
    return res


def decrypt (text, n = 3):
    res = ""
                   
    for i in range(0, len(text)):
        if text[i].isupper():
            res += back_shift(text[i], big_symbols, n)
        
        elif text[i].islower():
            res += back_shift(text[i], small_symbols, n)
        else:
            res += text[i]
        
    return res



str = encrypt(input())
print(str)
print(decrypt(str))

Рассмотрим подробнее второй вариант. Сначала я создал списки из русских букв верхнего и нижнего регистра. Далее идёт функция смещения (shift). Зачем функция? Чтобы не копипастить код, с различием только в списке букв для поиска.

Сама функция принимает на вход одну букву (ну, или надеется, что вы дадите 1 букву), список букв для поиска, смещение. Далее вычисляет индекс этой буквы в списке (метод find), потом проверяет, можно ли получить букву, смещённую на n позиций. Если да - возвращает эту букву. Если же нет, определяет букву по принципу Э →А, Ю →Б, Я →В и т. д. и всё равно возвращает изменённую букву.

Функция back_shift делает тоже самое, только наоборот.

И теперь интересное - функция encrypt. Она получает текст и смещение.

Зачем n=3, можно же просто n? Нельзя. Благодаря этому функция использует стандартное смещение (3), если не указано пользовательское. Иначе вы бы получали ошибку:

TypeError: encrypt() missing 1 required positional argument: 'n'

Далее запускается цикл for, который проходится по всей строке. Он проверяет - если буква text[i] является маленькой - запускает функцию смещения, как для маленькой буквы. И соответственно также для больших букв. (Вот он, плюс использовать функцию! Иначе пришлось бы копировать кусок кода от шифрования маленьких букв и менять список на список больших. И так каждый раз, когда нужно поменять регистр или язык символов... С функцией можно просто передавать, как аргумент список других букв.)

И если буква не является ни большой, ни маленькой - значит это другой символ (пробел, точка, кавычки и т.д.). В таком случае ничего не меняется.

И расшифровка, тоже самое, только наоборот (где-то я это уже видел...)

А вот и часть кода, которая выполнится при старте программы (наконец-то мы её нашли!). Она просто ждёт ввода пользователя - запускает шифрование, а потом дешифрирование.

P.S - пример с рекурсией выглядит красиво, но будет работать чуть медленнее, и при строках не больше 2000 - 3000 символов. (Такие уж в python ограничения).

→ Ссылка
Автор решения: павел

у вас res строка а вы прибавляете число

Traceback (most recent call last):
  File "D:\Python_Project\курс 2 урок 5 функции с переменным числом аргументов\Цезарь.py", line 53, in <module>
    encrypted = encrypt_caesar(msg, shift)
  File "D:\Python_Project\курс 2 урок 5 функции с переменным числом аргументов\Цезарь.py", line 26, in encrypt_caesar
    res += shift(text[i], big_symbols, n)
TypeError: 'int' object is not callable
→ Ссылка
Автор решения: Степан
def encrypt_caesar(msg, shift=3):
    small_symbols1 = "абвгдежзийклмнопрстуфхцчшщъыьэюя"
    big_symbols1 = "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ"
    shift = shift % len(small_symbols1)
    small_symbols2 = small_symbols1[shift:] + small_symbols1[:shift]
    big_symbols2 = big_symbols1[shift:] + big_symbols1[:shift]
    translation = msg.maketrans(small_symbols1 + big_symbols1, small_symbols2 + big_symbols2)
    return msg.translate(translation)


def decrypt_caesar(msg, shift=3):
    return encrypt_caesar(msg, -1 * shift)
→ Ссылка