Python四方密码解密爬山算法报错求助:字符串索引越界
四方密码解密程序字符串索引越界问题排查
尝试用Python实现基于爬山算法的四方密码解密程序,运行时出现字符串索引越界错误,怀疑与Python中用[0] * 5初始化列表的方式有关,以下是代码和错误说明:
主程序代码
import random import ngram_score2 as ns import copy from nltk.metrics import edit_distance from autocorrect import Speller spell = Speller(lang='en') fitness = ns.ngram_score('english_trigrams.txt') from nltk.metrics import edit_distance crypted = input("Enter the Cipher:\n") crypted_words = crypted.split(' ') cipher = list(set(crypted.replace(' ', ''))) key = ['uaomhyrtcsvkbfqixnzpldwe','uaomhyrtcsvkbfqixnzpldwe'] def score(key): points = 0 decr = dict(zip(cipher, key)) for word in crypted_words: decrypted_word = "".join([decr.get(l, '') for l in word]) points += fitness.score(decrypted_word) return points import re # Default table table = [['A', 'B', 'C', 'D', 'E'], ['F', 'G', 'H', 'I', 'J'], ['K', 'L', 'M', 'N', 'O'], ['P', 'R', 'S', 'T', 'U'], ['V', 'W', 'X', 'Y', 'Z']] def generate_table(key=''): alphabet = 'ABCDEFGHIKLMNOPRSTUVWXYZ' table = [[''] * 5 for _ in range(5)] key = re.sub(r'[\W]', '', key).upper() for row in range(5): for col in range(5): if len(key): table[row][col] = key[0] alphabet = alphabet.replace(key[0], '') key = key.replace(key[0], '') else: table[row][col] = alphabet[0] alphabet = alphabet[1:] return table def decrypt(keys, words): ciphertext = '' words = re.sub(r'[\W]', '', words).upper().replace('Q', '') R, L = generate_table(key[0]), generate_table(key[1]) for i in range(0, len(words), 2): digraphs = words[i:i + 2] ciphertext += unmangle(R, L, digraphs) return ciphertext.lower() def unmangle(R, L, digraphs): a = position(R, digraphs[0]) b = position(L, digraphs[1]) return table[a[0]][b[1]] + table[b[0]][a[1]] def position(table, ch): for row in range(5): for col in range(5): if table[row][col] == ch: return (row, col) return (None, None) def shuffle(key): a = random.randint(0, len(key) - 1) b = random.randint(0, len(key) - 1) a_v = key[a] b_v = key[b] am = list(key) am[b] = a_v am[a] = b_v return "".join(am) points = -1000000 max_points = points t = 1.0 freezing = 0.9999 while True: new_key = shuffle(key) p = score(new_key) if p > points: if p > max_points: max_points = p print("temperature", t) print("POINTS", p) print("KEY", new_key) sentence = decrypt(key, crypted) print(sentence) key = new_key points = p else: if random.random() < t: points = p key = new_key t *= freezing if t < 0.001: points = p break
ngram_score模块代码
''' Allows scoring of text using n-gram probabilities 17/07/12 ''' from math import log10 class ngram_score(object): def __init__(self,ngramfile,sep=' '): ''' load a file containing ngrams and counts, calculate log probabilities ''' self.ngrams = {} for line in open(ngramfile): key,count = line.split(sep) self.ngrams[key] = int(count) self.L = len(key) self.N = sum(self.ngrams.values()) #calculate log probabilities for key in list(self.ngrams.keys()): self.ngrams[key] = log10(float(self.ngrams[key])/self.N) self.floor = log10(0.01/self.N) def score(self,text): ''' compute the score of text ''' sc = 0 ngrams = self.ngrams.__getitem__ for i in range(len(text)-self.L+1): ngram = text[i:i+self.L].upper() #print(ngram) if ngram in self.ngrams: sc += ngrams(ngram) else: sc += self.floor return sc
错误说明
运行时出现字符串索引越界错误,怀疑与Python中用[0] * 5初始化列表的方式有关。
问题排查与修复方案
1. generate_table函数索引越界根源
函数中使用key.replace(key[0], '')会移除所有匹配字符,而非第一个,导致key被快速清空。后续循环中alphabet可能被取为空字符串,触发alphabet[0]索引越界。同时[0]*5初始化列表本身无问题,但字符处理逻辑错误。
修复后的generate_table:
def generate_table(key=''): alphabet = list('ABCDEFGHIKLMNOPRSTUVWXYZ') table = [[''] * 5 for _ in range(5)] # 密钥去重并保留顺序 key = list(re.sub(r'[\W]', '', key).upper()) unique_key = [] seen = set() for char in key: if char not in seen: seen.add(char) unique_key.append(char) key = unique_key idx = 0 for row in range(5): for col in range(5): if idx < len(key): table[row][col] = key[idx] if key[idx] in alphabet: alphabet.remove(key[idx]) idx += 1 else: table[row][col] = alphabet.pop(0) return table
2. unmangle函数空值风险
position可能返回(None, None),导致a[0]/b[0]触发错误,需添加判断:
def unmangle(R, L, digraphs): a = position(R, digraphs[0]) b = position(L, digraphs[1]) if None in a or None in b: return '' return table[a[0]][b[1]] + table[b[0]][a[1]]
3. shuffle函数参数错误
原函数把密钥列表当成单个字符串处理,需修改为处理单个密钥字符串:
def shuffle(key_str): key_list = list(key_str) a = random.randint(0, len(key_list) - 1) b = random.randint(0, len(key_list) - 1) key_list[a], key_list[b] = key_list[b], key_list[a] return "".join(key_list) # 主循环中生成新密钥的逻辑修改: while True: new_key0 = shuffle(key[0]) new_key1 = shuffle(key[1]) new_key = [new_key0, new_key1] p = score(new_key) # 后续逻辑不变
4. score函数逻辑错误
原函数用字符直接映射不符合四方密码逻辑,应调用decrypt生成完整文本后计算得分:
def score(key): decrypted_text = decrypt(key, crypted) return fitness.score(decrypted_text)
5. decrypt参数引用错误
函数内部误用全局变量key,应使用传入的keys参数:
def decrypt(keys, words): ciphertext = '' words = re.sub(r'[\W]', '', words).upper().replace('Q', '') R, L = generate_table(keys[0]), generate_table(keys[1]) for i in range(0, len(words), 2): digraphs = words[i:i + 2] if len(digraphs) < 2: continue ciphertext += unmangle(R, L, digraphs) return ciphertext.lower()
内容的提问来源于stack exchange,提问作者Max McInnes
相关产品推荐
相关产品推荐

