J. Ключевой секрет

Вася любит секреты и шифрование. Он часто пользуется шифром на основе замен и просит разработать вас функцию, которая позволит ему быстро шифровать сообщения.

Напишите функцию secret_replace, которая принимает:

  • текст требующий шифрования;
  • именованные аргументы — правила замен, представляющие собой кортежи из одного или нескольких значений.

Функция должна вернуть зашифрованный текст.

Примечание

Ваше решение должно содержать только функции.
В решении не должно быть вызовов требуемых функций.

Пример

Ввод

result = secret_replace("Hello, world!", l=("hi", "y"), o=("123", "z"))

Вывод

result = 'Hehiy123, wzrhid!'

Ввод

result = secret_replace(
    "ABRA-KADABRA",
    A=("Z", "1", "!"),
    B=("3",),
    R=("X", "7"),
    K=("G", "H"),
    D=("0", "2"),
)

Вывод

result = 'Z3X1-G!0Z371'

Решение

Задача не сильно сложная с одной стороны. С другой стороны я не знаю ни одного решения, которое бы полностью меня устроило. Каждое из предлагаемых решений проходит проверку, но каждое из них имеет недостаток.

Первое не очень элегантно, но бережно относится к входным данным.

Второе выглядит значительно лучше, но портит входной словарь. Проблему можно было бы решить глубоким копированием словаря, но это приводит нас или к использованию внешних модулей, или к теме рекурсий, с которой нам только еще предстоит познакомиться.

Третье решение базируется на втором, но предполагает использование cycle из itertools, который мы изучили ранее.

Во всех случаях алгоритм примерно одинаков – мы читаем букву и проверяем подлежит ли она замене, если подлежит, то запоминаем (через индекс, сдвиг или внешний модуль) использованную замену и переходим к следующей букве.

Ошибка в тесте Яндекса

Задача плохо покрыта тестами и по состоянию на 29-11-2023 позволяет пройти тест коду, который зацикливается на таком вызове:

print(secret_replace('a', a=('aa', 'aaa')))

Посмотреть код

Решение

Python
def secret_replace(text, **secrets):
    new_text = ''
    secrets = {key: [value, 0] for key, value in secrets.items()}
    for char in text:
        if char in secrets:
            pos = secrets[char][1] % len(secrets[char][0])
            new_text += secrets[char][0][pos]
            secrets[char] = [secrets[char][0], pos + 1]
        else:
            new_text += char
    return new_text

Решение

Python
def secret_replace(text, **code):
    new_text = ''
    for char in text:
        if char in code:
            new_text += code[char][0]
            code[char] = code[char][1:] + (code[char][0],)
        else:
            new_text += char
    return new_text

Решение

Python
from itertools import cycle


def secret_replace(text, **code):
    new_text = ''
    cycled_code = {char: cycle(replacements) for char, replacements in code.items()}
    for char in text:
        if char in cycled_code:
            new_text += next(cycled_code[char])
        else:
            new_text += char

    return new_text

Решение

Python
# Пример кода с ошибкой, который проходит тесты.

def secret_replace(text, **code):
    for item in code:
        while item in text:
            for substitution in code[item]:
                if item in text:
                    text = text[:text.find(item)] + substitution + text[text.find(item) + 1:]
    return text
Подписаться
Уведомить о
guest
13 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
Сергей
Сергей
22.12.2023 12:01

def secret_replace(text, **kwargs):
text_replace = ”
for i in range(len(text)):
if text[i] in kwargs:
text_replace += kwargs[text[i]][text[:i].count(text[i]) % len(kwargs[text[i]])]
else:
text_replace += text[i]
return text_replace`

Как вариант, можно рассмотреть такое решение, которое не ломается на print(secret_replace(‘a’, a=(‘aa’, ‘aaa’)))

Последний раз редактировалось 1 год назад Сергей Клочко ем
Артём
Артём
16.02.2024 23:11

def secret_replace(text, **enc):
    my_dict = {key: list(value) for key, value in enc.items()}
    result = ”
    for item in text:
        if my_dict.get(item):
            result += my_dict[item][0]
            my_dict[item].append(my_dict[item].pop(0))
        else:
            result += item
    return result

Денис
Денис
20.03.2024 15:28

Здравствуйте !
Как один из вариантов :

def secret_replace(text, **law):
s = ”
for i in range(len(text)):
s += law.get(text[i], text[i])[(text[:i].count(text[i])) % len(law.get(text[i], text[i]))]
return s

Egor
Egor
29.06.2024 16:48

def secret_replace(text, **replaces):
  for key in replaces:
    i = 0
    for _ in range(text.count(key)):
      j = text.find(key)
      text = text[:j] + replaces[key][i] + text[j + 1:]
      i += 1
      if i % len(replaces[key]) == 0:
        i = 0
  return text

Расул
Расул
24.07.2024 14:21

Проходит все тесты, как мне показалось, довольно лаконичное решение
def secret_replace(text, **replaces):
    new_text = ”
    slv = {key: 0 for key in replaces.keys()}
    for char in text:
        if char in replaces:
            new_text += replaces[char][(slv[char]) % len(replaces[char])]
            slv[char] += 1
        else:
            new_text += char
    return new_text

Алексей
Алексей
12.08.2024 20:57

Itertools подавали же ранее, значит можно по идее пользоваться

from itertools import cycle

def secret_replace(text, **replaces):
    replaces = {i: cycle(j) for i, j in replaces.items()}
    new_text = ”
    for i in text:
        if i in replaces:
            new_text += next(replaces[i])
        else:
            new_text += i
    return new_text

Алексей
Алексей
Ответить на  Сергей Клочко
13.08.2024 14:03

Исправился

from itertools import cycle, islice

def secret_replace(text, **replaces):
    replaces = {i: cycle(j) for i, j in replaces.items()}
    new_text = ”
    for i in text:
        if i in replaces:
            new_text += list(islice(replaces[i], 1))[0]
        else:
            new_text += i
    return new_text