2012-05-29 2 views
4

В моем уроке мне было поручено создать декодер Caesar Cipher, который берет строку ввода и находит наилучшую возможную строку, используя частоты букв. Если не уверен, сколько смысла это сделало, но позвольте задать вопрос:Python Caesar Cipher Decoder

Напишите программу, которая выполняет следующие действия. Во-первых, он должен прочитать одну строку ввода, которая является закодированным сообщением, и будет состоять из заглавных букв и пробелов. Ваша программа должна попробовать декодировать сообщение со всеми 26 возможными значениями сдвига S; из этих 26 возможных исходных сообщений напечатайте тот, который имеет высочайшую доброту. Для вашего удобства мы заранее определяем переменную letterGoodness для вас, список длины 26, который приравнивает значения в таблице частот выше

Letter Frequencies

У меня есть этот код до сих пор:

x = input() 
NUM_LETTERS = 26 #Can't import modules I'm using a web based grader/compiler 
def SpyCoder(S, N): 
    y = "" 
    for i in S: 
     x = ord(i) 
     x += N 
     if x > ord('Z'): 
      x -= NUM_LETTERS 
     elif x < ord('A'): 
      x += NUM_LETTERS 
     y += chr(x) 
    return y 

def GoodnessFinder(S): 
    y = 0 
    for i in S: 
     if x != 32: 
      x = ord(i) 
      x -= ord('A') 
      y += letterGoodness[x] 
    return y 

def GoodnessComparer(S): 
    goodnesstocompare = GoodnessFinder(S) 
    goodness = 0 
    v = '' 
    for i in range(0, 26): 
     v = SpyCoder(S, i) 
     goodness = GoodnessFinder(v) 
     if goodness > goodnesstocompare: 
      goodnesstocompare = goodness 
    return v 

y = x.split() 
z = '' 
for i in range(0, len(y)): 
    if i == len(y) - 1: 
     z += GoodnessComparer(y[i]) 
print(z) 

EDIT: внесенные изменения, предложенные Cristian Ciupitu Пожалуйста, проигнорируйте ошибки отступов, они, вероятно, возникли, когда я скопировал код.

Программа работает следующим образом:

  • Возьмите вход и разделить его в список
  • Для каждого значения списка я кормлю его в благости искателем.
  • Он берет доброту струны и сравнивает все остальное, и когда есть более высокая доброта, она делает более высокую ценность для сравнения.
  • Затем он сдвигает эту строку текста, я количество, чтобы увидеть, если благость выше или ниже

Я не совсем уверен, где проблема есть, первый тест: LQKP OG CV GKIJV DA VJG BQQ
Печати правильное сообщения: JOIN ME AT AT зоопарк

Однако следующий тест: UIJT JT B TBNQMF MJOF PG UFYU GPS EFDSZQUJOH
дает нежелательную строку: SGHR HR Z RZLOKD KHMD NE SDWS ENQ CDBQXOSHMF
Когда это должно быть: ЭТО ЛИНИЯ ОБРАЗЦОВ ТЕКСТА ДЛЯ ДЕКРИПТИНА G

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

Надеюсь, что мое объяснение имеет смысл, поскольку я в настоящий момент смущен.

+1

Если вы добавите 1 к каждому символу в мусорной строке «SGHR HR Z RZLOKD ...», вы получите «ЭТО ОБРАЗЕЦ ...», так что это почти правильно. –

+3

Вам следует попробовать заменить некоторые магические числа значимыми константами, например. 65 с 'ord ('A')', 26 с 'NUM_LETTERS'. Кстати, в 'GoodnessComparer' у вас есть' range (0, 25) 'вместо' (0, 26) '; это опечатка или нет? И еще: в 'GoodnessFinder' вам не нужно делать' ord (i) 'каждый раз, только когда' i' является пространством ('' ''). –

+0

[input()] (http://docs.python.org/library/functions.html#input) эквивалентно 'eval (raw_input())', что не имеет смысла, поэтому замените его на простой ' вызов raw_input() '. –

ответ

2

Мое окончательное решение, которое работает, благодаря замечательному Cristian Ciupitu.

x = input() 
NUM_LETTERS = 26 #Can't import modules I'm using a web based grader/compiler 
def SpyCoder(S, N): 
    y = "" 
    for i in S: 
     if(i.isupper()): 
     x = ord(i) 
     x += N 
     if x > ord('Z'): 
      x -= NUM_LETTERS 
     elif x < ord('A'): 
      x += NUM_LETTERS 
     y += chr(x) 
     else: 
     y += " " 
    return y 

def GoodnessFinder(S): 
    y = 0 
    for i in S: 
     if i.isupper(): 
     x = ord(i) 
     x -= ord('A') 
     y += letterGoodness[x] 
     else: 
     y += 1 
    return y 

def GoodnessComparer(S): 
    goodnesstocompare = GoodnessFinder(S) 
    goodness = 0 
    v = '' 
    best_v = S 
    for i in range(0, 26): 
    v = SpyCoder(S, i) 
    goodness = GoodnessFinder(v) 
    if goodness > goodnesstocompare: 
     best_v = v 
     goodnesstocompare = goodness 
    return best_v 


print(GoodnessComparer(x)) 

Спасибо за вашу помощь!

3

Вот моя реализация, которая отлично работает.

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

letterGoodness = dict(zip(string.ascii_uppercase, 
         [.0817,.0149,.0278,.0425,.1270,.0223,.0202, 
         .0609,.0697,.0015,.0077,.0402,.0241,.0675, 
         .0751,.0193,.0009,.0599,.0633,.0906,.0276, 
         .0098,.0236,.0015,.0197,.0007])) 

trans_tables = [ str.maketrans(string.ascii_uppercase, 
       string.ascii_uppercase[i:]+string.ascii_uppercase[:i]) 
       for i in range(26)] 

def goodness(msg): 
    return sum(letterGoodness.get(char, 0) for char in msg) 

def all_shifts(msg): 
    msg = msg.upper() 
    for trans_table in trans_tables: 
     txt = msg.translate(trans_table) 
     yield goodness(txt), txt 

print(max(all_shifts(input()))) 
+1

Вы заметили тег * homework *, верно? Ваш ответ слишком хорош. –

+1

@CristianCiupitu: Поэтому он не может просто представить его, но сначала учиться. – Kabie

0

Я работаю над одним и тем же учебником и использовал несколько иной метод. Это избежать создания и вызова функции:

inp = input()  #to hold code text 
code = list(inp) #store code as a list 
soln = []   #store the 'Goodness' for each of 26 possible answers 
y=0    #variable to hold total goodness during calculations 
clear = []  #will hold decoded text 
pos=0    #position marker for a list 

#for every possible value of shift 
#note range as 0 to 25 are valid shifts and shift 26 = shift 0 

for shift in range(0,26): 
    for i in code:     #loop through each letter in code 
     if i == " ":     #spaces have no score so omit them 
     continue 
     else:      #if it's a letter 
     x = ord(i)-shift   #apply the test shift 
     if x < 65:    #prevent shifting outside A-Z range 
      x = x + 26    
     x = x - 64    #turn ord into character position in A-Z with A=1 
     x = letterGoodness[x-1] #turn this into the Goodness score 
     y = y + x     #add this to a running total 
    soln.insert(shift-1,y)   #AFTER decoding all letters in code, add total(y) to list of scores 
    y = 0       #reset y before next test value 

bestSoln=max(soln)     #find highest possible score 

for i in range(0,26):    #check the list of solutions for this score 
    if soln[i]==bestSoln:   #the position in this list is the shift we need 
     bestShift = i+1    #+1 as the first solution is 0 

for i in code:      #now decode the original text using our best solution 
    if i == " ":     #spaces are not encoded so just add these to the string 
     clear.insert(pos," ")  #pos used to track next position for final string 
     pos = pos + 1 
     continue 
    else: 
     x = ord(i)-bestShift   #same operation as before 
     if x < 65: 
     x = x + 26 
    z = chr(x) 
    clear.insert(pos,z)    #add the decoded letter to the clear text 
    pos = pos + 1 
print("".join(clear))    #join the list of clear text into one string and print it 

Обратите внимание, что многие части этого кода может (и должен) быть сжат, например

x = x - 64 
x = letterGoodness[x-1] 
y = y + x 

Они оставили расширен «показать свою работу» для учебное упражнение.