You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 18:54:53