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

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

Для этого мне приходится искать символ в 2-х списках, список строчных букв, прописных букв, а потом, если это не буква, просто добавить символ в зашифрованную строку.

Для этого я решил использовать два слоя try и exclude. Есть ли лучший способ сделать это, может быть, с if/else?

import string
from tkinter import *
from tkinter import ttk

alphaLower = string.ascii_lowercase
alphaUpper = string.ascii_uppercase
alphaShiftL = alphaLower
alphaShiftU = alphaUpper

def shiftList(amount):
    global alphaShiftL
    global alphaShiftU
    alphaShiftL = alphaLower[amount:] + alphaShiftL[:amount]
    alphaShiftU = alphaUpper[amount:] + alphaShiftU[:amount]

def encrypt(unencrypted):
    encrypted = ''
    for char in unencrypted:
        #HERE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        try: 
            alphaLower.index(char)
            encrypted += alphaShiftL[alphaLower.index(char)]
        except ValueError:
            try:
                encrypted += alphaShiftU[alphaUpper.index(char)]
            except ValueError:
                encrypted += char

    return encrypted

person Community    schedule 23.02.2016    source источник
comment
Используйте find вместо index и вообще избегайте исключений.   -  person Matteo Italia    schedule 24.02.2016


Ответы (4)


Есть более эффективные способы реализовать это. Но работая с тем, что у вас есть, первое, что я мог бы порекомендовать, это объединить списки, чтобы вам потребовалась только 1 попытка/исключение:

alpha = alphaLower + alphaUpper
alphaShift = alphaShiftL + alphaShiftU
for char in unencrypted:
try: 
    encrypted += alphaShift[alpha.index(char)]
except ValueError:
    encrypted += char

Теперь у нас есть только одна попытка/за исключением того, что хорошо.


Мы можем добиться большего — гораздо лучшего результата — если продолжим работать только с одним объектом, содержащим сопоставление. В этом случае вам действительно нужно сопоставить символ в alpha с другим символом в alphaShift. Мы можем сделать это тривиально с помощью python dict:

mapping = dict(zip(alpha, alphaShift))
for char in unencrypted:
    encrypted += mapping.get(char, char)

Или, более эффективно:

mapping = dict(zip(alpha, alphaShift))
encrypted = ''.join(mapping.get(char, char) for char in unencrypted)

Чтобы «расшифровать», вам просто нужно обратное отображение:

inverse_mapping = dict(zip(alphaShift, alpha))
unencrypted = ''.join(inverse_mapping.get(char, char) for char in encrypted)
person mgilson    schedule 23.02.2016
comment
Но использование одного списка внесет некоторые сложности в shiftList. Хотя есть и лучший способ реализовать это, но он будет полностью отличаться от того, что есть у OP. - person gil; 24.02.2016
comment
В качестве дополнения к комментарию Гилла; если буква z, а сдвиг 4, ваше решение будет D. - person zondo; 24.02.2016
comment
@gill - я не думаю, что это действительно усложняет. Может быть, это уже не настоящий шифр Цезаря — я думаю, это два склеенных шифра — но он по-прежнему работает точно так же. Важно то, что OP использует несколько списков для сопоставления одного символа с другим. Пока это сопоставление четко определено и используется последовательно (а так оно и есть), не имеет значения, хранится ли оно в одном списке или в двух. . . - person mgilson; 24.02.2016
comment
@JackyXie - это выражение генератора. Если вы еще не узнали о них (или их родственных конструкциях list-comprehensions), они действительно круты и заслуживают внимания. На данный момент вы можете считать его эквивалентным циклу выше. - person mgilson; 24.02.2016
comment
Мне кажется, что OP хочет, чтобы шифрование сохраняло регистр. Если да, то shiftList нужно изменить (в более сложном направлении), чтобы он работал с вашим решением, и это все, что я говорил. ОП может сказать нам, что он согласен с изменением регистра, но я бы не догадался об этом из вопроса. - person gil; 24.02.2016
comment
@gill Я изменил shiftList на alphaShift = ALPHA[количество:26] + ALPHA[0:количество] + ALPHA[26+количество:] + ALPHA[26:26+количество] Теперь мне нужно получить это до 79 символов. - person ; 24.02.2016

if char.islower():
    encrypted += alphaShiftL[alphaLower.index(char)]
elif char.isupper():
    encrypted += alphaShiftU[alphaUpper.index(char)]
else:
    encrypted += char

См. документацию здесь и здесь.

person gil    schedule 23.02.2016

Если я правильно понимаю, вам просто нужно знать, присутствует ли что-то в списке. Вы можете проверить включение коллекции следующим образом:

if search in collection:
    ix = collection.index(search)
else:
    //handle no

Я вас правильно понял?

Изменить: решение mgilson, потому что вам нужен индекс элемента.

ix = collection.find(search)
if ix != -1:
    //handle yes
else:
    //handle no
person saarrrr    schedule 23.02.2016

Если это не академическое упражнение, я не понимаю, почему вы так организуете свой код. Если вы страстно хотите хранить информацию в массивах, вы можете просто объединить их вместе, чтобы обойтись одним поиском.

alphaLower = string.ascii_lowercase
alphaUpper = string.ascii_uppercase
alpha = alphaLower + alphaUpper
alphaShift = alpha

def shiftList(amount):
    global alphaShiftL
    global alphaShiftU
    alphaShiftL = alphaLower[amount:] + alphaShiftL[:amount]
    alphaShiftU = alphaUpper[amount:] + alphaShiftU[:amount]
    alphaShift = alphaShiftL + alphaShiftU

Теперь вы можете выполнять поиск напрямую:

def encrypt(unencrypted):
    encrypted = ''
    for char in unencrypted:
        idx = alpha.find(char)
        encrypted += alphaShift[idx] if idx >= 0 else char
    return encrypted

Однако было бы гораздо лучше просто использовать словарь:

lc = string.ascii_lowercase
uc = string.ascii_uppercase

cipher = dict(zip(lc+uc, lc[13:]+lc[:13]+uc[13:]+uc[:13]))

def encrypt(input):
    return ''.join(cipher.get(c,c) for c in input)
person unpythonic    schedule 23.02.2016