【问题标题】:Finding words in a non-spaced paragraph?在非空格段落中查找单词?
【发布时间】:2013-12-19 23:23:35
【问题描述】:

我正在使用 python 构建一个凯撒密码解密器,它可以工作并解密已经加密的单词。但是,它显示了它所有的暴力解密尝试,例如,用密钥 3 加密的“HELLO”是 KHOOR。解密后的结果是“KHOORJGNNQIFMMPHELLOGDKKNFCJJMEBIILDAHHKCZGGJBYFFIAXEEHZWDDGYVCCFXUBBEWTAADVSZZCURYYBTQXXASPWWZROVVYQNUUXPMTTWOLSSVNKRRUMJQQTLIPPS”我想知道是否有一种方法可以使用带有 Python 的字典在此输出中搜索英文单词,或者我可以改进我的代码以仅打印出已知的英文单词。抱歉,如果以前有人问过这个问题,我四处搜寻,似乎找不到合适的东西。

【问题讨论】:

  • 看来字母频率会很有帮助,还有字母对频率
  • @JoranBeasley 所说的是替代密码的密码分析的标准方法。安德鲁,你应该坚持下去。
  • 请查看我的答案的编辑。我使用频率实现了一种天真的方法。
  • 我认为,如果您可以选择修改原始代码以仅打印出有效的英文单词,那可能是解决您问题的最佳方法。如果您别无选择,只能从不带标点的块中破译文本,则此处答案中讨论的密码分析很有趣且很有用,但它可能并不比从一开始就修复输出更好。

标签: python encryption dictionary


【解决方案1】:
englishWords = ['HELLO', 'ME', 'AXE', 'FOO', 'BAR', 'BAZ'] #and many more
cypher = 'KHOORJGNNQIFMMPHELLOGDKKNFCJJMEBIILDAHHKCZGGJBYFFIAXEEHZWDDGYVCCFXUBBEWTAADVSZZCURYYBTQXXASPWWZROVVYQNUUXPMTTWOLSSVNKRRUMJQQTLIPPS'

for word in englishWords:
    if word not in cypher: continue
    print('Found "{}"'.format(word))

这会产生:

Found "HELLO"
Found "ME"
Found "AXE"

如果这是关于看,如果解密文本的密钥是正确的,即如果结果可能是英文单词,我不会寻找单词,而是尝试在结果中找到不符合的簇用英文音节partus。


这是一个非常简单的字母频率扫描实现:

#! /usr/bin/python3

plain = 'Z RD NFEUVIZEX ZW KYVIV ZJ R NRP KF LJV R UZTKZFERIP NZKY GPKYFE KF JVRITY WFI RE VEXCZJY NFIU ZE KYZJ FLKGLK FI TRE Z ZDGIFMV DP TFUV KF FECP GIZEK FLK BEFNE VEXCZJY NFIUJ. RGFCFXZVJ ZW KYZJ YRJ SVVE RJBVU SVWFIV, Z JVRITYVU RIFLEU REU TFLCUE\'K JVVD KF WZEU KYV IZXYK KYZEX.'.upper ()

freqs = {'E': 12.7, 'T': 9.1, 'A': 8.2, 'O': 7.5, 'I': 7.0}

def cypher(text, key):
    return ''.join(chr((ord(c) - ord('A') + key) % 26 + ord('A')) if 'A' <= c <= 'Z' else c for c in text)


def crack(text):
    length = len(text)
    best = 100000
    bestMatch = ''
    for key in range(26):
        cand = cypher(text, key)
        quality = 0
        for l, c in {letter: sum(1 for c in cand if c == letter) for letter in 'ETAOI'}.items():
            quality += (c / length - freqs[l]) ** 2
        if quality < best:
            best = quality
            bestMatch = cand
    return bestMatch

print(crack(plain))

这里有三个例子:

Input: TQ ESTD TD LMZFE DPPTYR, TQ ESP VPJ QZC OPNJASPCTYR L EPIE TD ESP NZCCPNE ZYP, T.P. TQ ESP CPDFWE XTRSE MP PYRWTDS HZCOD, T HZFWOY'E WZZV QZC HZCOD, MFE ECJ EZ QTYO NWFDEPCD TYDTOP ESP CPDFWE HSTNS OZ YZE NZXAWJ HTES ESP PYRWTDS DJWWLMWP LALCEFD.

Output: IF THIS IS ABOUT SEEING, IF THE KEY FOR DECYPHERING A TEXT IS THE CORRECT ONE, I.E. IF THE RESULT MIGHT BE ENGLISH WORDS, I WOULDN'T LOOK FOR WORDS, BUT TRY TO FIND CLUSTERS INSIDE THE RESULT WHICH DO NOT COMPLY WITH THE ENGLISH SYLLABLE APARTUS.

Input: KWSJUZAFY XGJ WFYDAKZ OGJVK AF S TDGUC GX MFVAXXWJWFLASLWV LWPL DACW LZSL AK UWJLSAFDQ HGKKATDW, SFV VGAFY AL WXXAUAWFLDQ AK S YWFMAFWDQ AFLWJWKLAFY HJGTDWE. TML AL'K HJGTDWESLAU XGJ DGLK GX JWSKGFK, BMKL GFW GX OZAUZ AK LZSL QGMJ WFUJQHLWV LWPL ESQ AFUDMVW LWPL LZSL JSFVGEDQ ZSHHWFK LG XGJE SF WFYDAKZ OGJV UGEHDWLWDQ TQ UZSFUW.

Output: SEARCHING FOR ENGLISH WORDS IN A BLOCK OF UNDIFFERENTIATED TEXT LIKE THAT IS CERTAINLY POSSIBLE, AND DOING IT EFFICIENTLY IS A GENUINELY INTERESTING PROBLEM. BUT IT'S PROBLEMATIC FOR LOTS OF REASONS, JUST ONE OF WHICH IS THAT YOUR ENCRYPTED TEXT MAY INCLUDE TEXT THAT RANDOMLY HAPPENS TO FORM AN ENGLISH WORD COMPLETELY BY CHANCE.

Input: QZC PILXAWP, UFDE ESP EPIE JZF'GP AZDEPO SPCP TYNWFOPD SPWW, TQ, WTA, WZR, LDA LYO ACZMLMWJ ZESPCD. JZF NZFWO ECTX OZHY ESP LWEPCYLETGPD MJ ZYWJ DPLCNSTYR QZC HZCOD ESP DLXP WPYRES LD JZFC ELCRPE HZCO, LYO ZYWJ QZC HZCOD HTES ESP DLXP WPEEPC ALEEPCY. MFE ESLE'D CPLWWJ BFTEP L WZE ZQ HZCV EZ RPE LCZFYO ESP QLNE ESLE JZFC TYTETLW ZFEAFE SLD L WZE ZQ FDPWPDD OLEL TY TE.

Output: FOR EXAMPLE, JUST THE TEXT YOU'VE POSTED HERE INCLUDES HELL, IF, LIP, LOG, ASP AND PROBABLY OTHERS. YOU COULD TRIM DOWN THE ALTERNATIVES BY ONLY SEARCHING FOR WORDS THE SAME LENGTH AS YOUR TARGET WORD, AND ONLY FOR WORDS WITH THE SAME LETTER PATTERN. BUT THAT'S REALLY QUITE A LOT OF WORK TO GET AROUND THE FACT THAT YOUR INITIAL OUTPUT HAS A LOT OF USELESS DATA IN IT.

这是最后一个没有空格和标点符号的例子:

Input: ZRDLJZEXGPKYFEKFSLZCURTRVJRITZGYVIUVTIPGKVIZKNFIBJREUUVTIPGKJKYVRCIVRUPVETIPGKVUNFIUYFNVMVIZKJYFNJRCCZKJ SILKVWFITVUVTIPGKZFERKKVDGKJWFIVORDGCVYVCCFVETIPGKVUNZKYRBVPFW3ZJBYFFI

Output: IAMUSINGPYTHONTOBUILDACAESARCIPHERDECRYPTERITWORKSANDDECRYPTSTHEALREADYENCRYPTEDWORDHOWEVERITSHOWSALLITS BRUTEFORCEDECRYPTIONATTEMPTSFOREXAMPLEHELLOENCRYPTEDWITHAKEYOF3ISKHOOR

【讨论】:

  • 我添加了一些例子。
【解决方案2】:

在这样的未区分文本块中搜索英语单词当然是可能的,并且有效地进行搜索是一个真正有趣的问题。但这有很多原因,其中一个是您的加密文本可能包含随机恰好完全偶然形成一个英文单词的文本。

例如,仅您在此处发布的文本包括 HELLIFLIPLOG , ASP 可能还有其他。您可以通过仅搜索与目标单词长度相同的单词并且仅搜索具有相同字母模式的单词来减少备选方案。但要解决初始输出中包含大量无用数据这一事实,确实需要做很多工作。

您可以通过以下操作轻松检查特定单词是否在英语词典中:

  1. 从字典文件中读取行(大多数系统上为/usr/share/dict/words)。
  2. 去除空白,转换为小写并将每一行存储在 Python 字典中。
  3. 解密每个单词后,检查它是否作为关键字出现在 Python 字典中。

采用这种方法可能比试图通过无间隔的初始输出卑躬屈膝更有意义。

【讨论】:

  • 解决该问题的一种方法(在处理数据段落而不是单个单词时)是要求基于字符总数的最少匹配数。
猜你喜欢
  • 2020-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-12
  • 1970-01-01
  • 1970-01-01
  • 2014-05-16
  • 1970-01-01
相关资源
最近更新 更多