Python 凯撒密码解码器

5

我的任务是创建一个凯撒密码解码器,它接受一个输入字符串,并使用字母频率找到最佳的字符串。如果不确定这句话的意思,请看下面的问题:

编写一个程序,完成以下操作。首先,应读取一行输入,这是加密消息,由大写字母和空格组成。您的程序必须尝试使用所有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)

编辑:按Cristian Ciupitu的建议进行更改

这个程序的工作原理如下:

  • 获取输入并将其分割为列表
  • 对于每个列表值,我都会将其提供给好度量查找器。
  • 它获取字符串的好度,并将所有其他内容与之进行比较,当存在较高的好度时,它会将较高的好度作为要比较的好度。
  • 然后,它将文本字符串向右移i个单位以查看好度是更高还是更低。

我不确定问题出在哪里,第一个测试:LQKP OG CV GKIJV DA VJG BQQ
显示正确的消息:JOIN ME AT AT BY THE ZOO

但是下一个测试:UIJT JT B TBNQMF MJOF PG UFYU GPS EFDSZQUJOH
给出了一个垃圾字符串:SGHR HR Z RZLOKD KHMD NE SDWS ENQ CDBQXOSHMF
而实际上应该是:THIS IS A SAMPLE LINE OF TEXT FOR DECRYPTING

我知道我必须:
尝试每个移位值
获得单词的“好度”
返回具有最高好度的字符串。

希望我的解释有意义,因为我现在很困惑。


1
如果你将垃圾字符串'SGHR HR Z RZLOKD ...'中的每个字符加1,你会得到'THIS IS A SAMPLE ...',因此它几乎是正确的。 - Jim Ferrans
3
你应该尝试用有意义的常数替换一些神奇数字,例如将65替换为ord('A'),将26替换为NUM_LETTERS。顺便提一下,在“GoodnessComparer”中,你使用了range(0, 25)而不是(0, 26),这是一个笔误还是故意的?另外一件事:在“GoodnessFinder”中,你不需要每次都执行“ord(i)”,只有当“i”是空格(' ' )时才需要。 - Cristian Ciupitu
1
@Cristian Ciupitu:那应该是Python 3代码。 - Kabie
@Thegluestickman:NUM_LETTERS只是一个例子。你仍然需要声明它,或者如果你想的话,你可以导入string模块并使用len(string.ascii_uppercase) - Cristian Ciupitu
1
由于Stack Overflow允许您回答自己的问题,而这是一项作业,因此您应该发布解码器的最终版本。 - Cristian Ciupitu
显示剩余10条评论
5个回答

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())))

2
你注意到了“作业”标签,对吧?你的回答太好了。 - Cristian Ciupitu
1
@CristianCiupitu:所以他不能只是提交它,而是要先学习。 - Kabie

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

感谢您的所有帮助!涉及IT技术相关内容。

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

它们被展开以“展示我的工作”,用于教程练习。


0
def start():
   message = input()                                        ## collect user input
   maxGoodness = 0                                          ## stablish a benchmark
   maxGoodnessMessage = message                             ## use current message as baseline
   for i in range(0,26):                                    ## for each range of 1-26 the range of the alphabet and goodness
      currentMessage = decodeMesssage(message, i)           ## decode the message for the current i
      currentGoodness = calculateGoodness(currentMessage)   ##  calculate the goodness for decoded message
      if currentGoodness > maxGoodness:                     ## compare goodness to last iteration, if greater
         maxGoodness = currentGoodness                      ## update maxGoodness
         maxGoodnessMessage = currentMessage                ## store decipher message with current max goodness
         
   print(maxGoodnessMessage)

def decodeMesssage(message, S):                             ## decode message
   newMessage = ''                                          ## start with an empty message 
   for letter in message:                                   ## for each letter in the message 
      if ord(letter) == 32:                                 ## if we get an empty character just add it to the message and continue to next iteration
        newMessage = newMessage + letter
        continue
      currentAscii = ord(letter) + S                        ## calculate the value of the current letter and add the S= value
      if currentAscii > 90:                                 ## if the value of current letter + S is 90 meaning letter Z
         currentAscii = currentAscii-26                     ## find next letter starting from A
      newMessage += str(chr(currentAscii))                  ## transform back to a letter and add to message
   return newMessage 
 
def calculateGoodness(message): 
   total = 0
   for char in message:                                     ## for each character in the message
      if char == ' ':                                       ## ignore empty characters
         continue
      i = ord(char)
      total += letterGoodness[i-65]                        ## calculate the  value of the character and add it to total
   return total
      
   
   
start()

0
letterGoodness = {'A': 8.17, 'B': 1.49, 'C': 2.78, 'D': 4.25, 'E': 12.70,
                  'F': 2.23, 'G': 2.02, 'H': 6.09, 'I': 6.97, 'J': 0.05, 
                  'K': 0.77, 'L': 4.02, 'M': 2.41, 'N': 6.75, 'O': 7.51, 
                  'P': 1.93, 'Q': 0.09, 'R': 5.99, 'S': 6.33, 'T': 9.06, 
                  'U': 2.76, 'V': 0.98, 'W': 2.36, 'X': 0.15, 'Y': 1.97, 
                  'Z': 0.07} 
                  
# em - input message
em = str(input()) 
em = em.upper()

# dm - guess message
dm = '' 
dmList = []
goodnessList = []
shift = 1

for g in range(25):
   goodness = 0
   dm = ''
   for i in em:
       newL = chr(ord(i) - shift)
       if i == ' ':
            dm += i

       elif ord(newL) < 65:
               A = ord(newL) + 90
               newL = chr(A - 64)
               dm += newL

       else:
            dm += newL

   for h in dm:
      if h != ' ':
         goodness += letterGoodness[h]
   goodnessList.append(goodness)
         
   shift += 1
   dmList.append(dm)  

highestG = max(goodnessList)
dmind = goodnessList.index(highestG)
print(dmList[dmind])

目前你的回答不够清晰。请编辑并添加更多细节,以帮助其他人理解它如何回答所提出的问题。你可以在帮助中心找到有关如何撰写好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接