Как я могу решить проблему с кодом Цезаря в Python - PullRequest
4 голосов
/ 03 февраля 2020

Я пытаюсь создать простую функцию кода Цезаря, которая должна расшифровывать строку, заданную во входных данных.

Очистить текст = AB C DEFGHIJKLMNOPQRSTUVWX YZ

Encrypted = DEFGHIJKLMNOPQRSTUW YZAB C

Это мой код для 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'

и поэтому, когда первая расшифрованная буква равна второй зашифрованной букве.

Как я могу изменить свой код? где ошибка? Я знаю, что в inte rnet есть много других способов сделать то же упражнение, но теперь мне интересно понять ошибку МОЕГО кода.

Ответы [ 3 ]

3 голосов
/ 03 февраля 2020

Давайте использовать ваш пример deciph('sp'). Проблема в том, что когда вы делаете s=s.replace(i,b[j]), вы вначале заменяете все экземпляры 's' на 'p', давая вам s = 'pp', а затем на втором проходе заменяете все экземпляры 'p' на 'm', давая вам s = 'mm'. Это можно исправить, удерживая новую начальную переменную rv = '', а затем используя rv+=b[j] для каждой буквы вместо изменения s. Затем в конце просто верните rv.

2 голосов
/ 03 февраля 2020

Как уже упоминалось, проблема, с которой вы сталкиваетесь, связана с тем, что каждый символ в s безоговорочно заменяет «чистый» - поскольку a и b состоят из одинаковых букв, а 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 встроенного введите : a 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)

Как видите, алгоритм на намного проще. Это также намного быстрее (поиск dict 0 (1) и высоко оптимизирован), и потребляет меньше памяти (нет необходимости для промежуточного списка result).

В программировании выбор правильной структуры данных является ключевым ...

NB:

теперь мне интересно понять ошибку МОЕГО кода.

Это очень похвально, если не сказать больше - Я бы sh все здесь сделали бы то же самое. Теперь это то, что вы могли бы решить самостоятельно с помощью самой простой и простой c технологии отладки c: отслеживание выполнения кода путем распечатки вашего текущего состояния в стратегии c моменты:

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'
1 голос
/ 03 февраля 2020

Вы можете использовать метод find(), чтобы найти положение символов в al oop.

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
...