Python微实践 - 布莱切利庄园的秘密

news/2025/1/15 13:54:14/

二战时期,英国数学家、计算机科学之父Alan Turing在布莱切利庄园成功破译了德军密码,为赢得世界反法西斯战争的胜利做出了重大贡献。为了表达对前辈先贤的敬意,本微实践取名为“布莱切利庄园的秘密”。

本文引用自作者编写的下述图书; 本文允许以个人学习、教学等目的引用、讲授或转载,但需要注明原作者"海洋饼干叔
叔";本文不允许以纸质及电子出版为目的进行抄摘或改编。
1.《Python编程基础及应用》,陈波,刘慧君,高等教育出版社。免费授课视频 Python编程基础及应用
2.《Python编程基础及应用实验教程》, 陈波,熊心志,张全和,刘慧君,赵恒军,高等教育出版社Python编程基础及应用实验教程
3. 《简明C及C++语言教程》,陈波,待出版书稿。免费授课视频

在人类尚未获得足够的算力之前,加密和解密都是手工进行的。受限于有限的人工算力,加解密只能采取一些简单的方法,比如下面这种:
在这里插入图片描述
信息的发送方和接收方同时持有如上表所示的明密文字母对照表,该对照表对任何第三方保密。加密时,按照该对照表,将明文中的a映射为f,b映射为v,…,z映射为t,即得密文。解密时,同样按照该对照表,将密文中的f映射为a,v映射为b,…,t映射为z,即得明文。

在随书代码的CH6子目录下,文件article.txt包含了示例中的“明文”,其内容引自一本著名的英文小说:

A few days later, Tom invites Nick to a party in New York City. On the way, Tom picks up his ...

通过执行CH6子目录下的encode.py,可以将明文article.txt按前述加密方法加密成密文,文件名为encoded.txt:

f izg dfho efuzj, ulq sansuzo asrw ul f bfjuh sa azg hljw rsuh. la uyz gfh, ulq bsrwo cb yso ...

看起来,即便密文被第三方截获,也难以解读,实则不然。在正常的英文表达中,每个字母出现的频率是有差异的,比如e的出现频次通常最高的,而z、x、q则相较较低。这提供了一种解密思路:对密文中的字母出现频率进行统计,其中出现次数最高者极可能是e,次高者可能是t,最低者则可能是z、x或者q。

应用上述解密思路,我们设计了下述解密程序:

#decode.py
f = open("encoded.txt")     #打开并读取密文内容至s
s = f.read().lower()        
f.close()stats = {}                  #对密文中的字母出现次数进行统计
for c in s:if c.isalpha():stats[c.lower()] = stats.get(c.lower(),0) + 1stats = list(stats.items()) #将字典转换为列表,对字母按出现次数降序排序
stats.sort(key=lambda x:x[1],reverse=True)
stats = "".join([x[0] for x in stats])
print("密文统计的按频次降序排列的英文字母:", stats)codes = "etansoirhldygmcubwfkvpjzxq"
print("语料统计的按频次降序排序的英文字母:",codes)r = ""                      #进行解密,明文存于r
for c in s:if c.isalpha():r += codes[stats.index(c)]else:r += cf = open("decoded.txt","wt")  #将明文r写入文件
f.write(r)
f.close()
print("解密完成: decoded.txt")

🚩第2 ~ 4行:打开当前工作路径下的密文文件encoded.txt,将其中的内容按字符串形式读出,保存在变量s中。使用Python进行文件读写的详细方法,我们在第8章中讨论。请读者留意第3行中lower()函数的存在,在整个解密过程中,我们统一使用小写字母。

🚩第6 ~ 9行:借助于字典stats对密文中各字母的出现次数进行统计。统计完成后,stats中将得到形如{“a”:112, “x”:7, … “z”:3}的结果数据。统计过程中,我们使用for循环对密文s中的字符c逐一进行处理,如果字符c是英文字母(使用成员函数isalpha()进行判断),则将其在字典中的出现次数加1。请读者留意get()函数的运用,当某个字母是首次发现时,其在字典中尚不存在,此时,get()函数将返回默认值0。

🚩第11 ~ 14行:通过列表按统计的频次对字母进行降序排序。在字典中,键值对之间没有前后之分,因此排序只能通过列表进行。第11行将字典的键值对转换为列表,其内容形式为:[(“a”,112),( “q”,3),…,(“x”,7)]。第12行使用sort()函数对该列表进行排序,排序时通过匿名函数获取每个元组的下标1值,即频次做为排序依据。第13行使用列表推导语法将有序列表中的字母单独提取出来,并使用空字符串””将所有字母串接在一起。如执行结果的第1行所示,stats字符串的值为zufaolsjyedhpqrcvgiwnbmtkx,这表明在密文中,出现频次最高的是z,然后是u,f,出现频次最低是x。

🚩第16行:字符串codes给出了从正常语料库中统计的字母出现频次的降序排列。

🚩第19 ~ 24行:按照字母频次的统计结果,进行解密。字符串stats给出了密文统计的字母频次降序排列,字符串codes则给出了正常语料统计的字母频次降序排列。粗略地,我们认为,密文字母stats[i]对应的明文字母即为codes[i]。在下述统计结果中,z在密文中出现频次最高,我们认为它对应明文字母e;u在密文中出现频次为第二高,我们认为它对应明文字母t。

密文统计的按频次降序排列的英文字母: zufaolsjyedhpqrcvgiwnbmtkx    [stats]
语料统计的按频次降序排序的英文字母: etansoirhldygmcubwfkvpjzxq    [codes]

解密过程中,我们使用for循环逐一处理密文s中的字符c。如果字符c是字母(isalpha()),首先通过stats.index©找到它在密文中的频次排位,然后再以该频次排位作为下标,从codes中获得对应的明文字母,并将明文字母附加至明文字符串r。举例,假设c为字母”f”,stats.index©的结果为下标2,对照codes[2],明文字母即为”a”。如代码的第23 ~ 24行所示,对于那些不是字母的密文字符,直接将其附加至明文字符串r。

🚩第26 ~ 28行:将解密所得的明文字符串r写入文件decoded.txt。

使用Visual Studio Code打开解密文件decoded.txt,可见解密结果是正确的:

a few days later, tom invites nick to a party in new york city. on the way, tom picks up his ...

需要说明的是,由于密文较短,其字母频次统计结果不一定能与正常语料统计的字母频次完美对应。此时,按上述方法得到解密结果可能并不十分准确,比如z被错误解读成了q。在多数字母被正确解密的情况下,少数字母的错误对应关系容易通过人工进行校正。

源程序、数据文件下载: 请在浏览器中复制并录入下述地址
源程序、数据文件下载

为了帮助更多的年轻朋友们学好编程,作者在B站上开了两门免费的网课,一门零基础讲Python,一门零基础C和C++一起学,拿走不谢!

简洁的C及C++
由编程界擅长教书,教书界特能编程的海洋饼干叔叔打造
Python编程基础及应用
由编程界擅长教书,教书界特能编程的海洋饼干叔叔打造

如果你觉得纸质书看起来更顺手,目前Python有两本,C和C++在出版过程中。

Python编程基础及应用

Python编程基础及应用实验教程
在这里插入图片描述


http://www.ppmy.cn/news/812447.html

相关文章

JavaSE学习笔记 基于Socket的TCP网络编程

网络编程 1.网络编程的基本知识回顾1.1 C/S与B/S结构1.2 网络编程的三要素解析1.2.1 IP地址1.2.2 端口号1.2.3 网络协议 2.Socket通信简述3.基于TCP协议的网络编程3.1 基于TCP协议的网络通信程序结构3.2 案例:一个客户端与服务器单次通信3.3 案例:多个客…

web渗透a

Nmap namp 192.168.1.1 namp -A -T4 -V 192.168.1.1 -A :开启操作系统识别和版本识别功能 -T :0-6档,设置扫描的快慢 0最慢,6最快; //级别越高你,对网络宽带要求越高,另外扫描太快&#xf…

PowerShell攻击指南

文章目录 一:PowerShell简介1.1:基本概念1.2:执行策略与绕过1.3:常用命令 二:PowerSploit2.1:PowerSploit安装2.2:PowerSploit攻击实战2.2.1:直接shellcode反弹meterpreter shell2.2…

嵌入式Linux C笔试题积累

http://blog.csdn.NET/h_armony/article/details/6764811 1. 嵌入式系统中断服务子程序(ISR) 中断是嵌入式系统中重要的组成部分,这导致了很 多编译开发商提供一种扩展—让标准C支持中断。具代表事实是,产生了一个新的关键字 __interrupt。下面的代码…

网络安全必备网络基础知识一

写在前面,这玩意写的我头疼,虽然也是照着资料敲键盘,但是很多内容都没有展开,毕竟网络知识太多太多了,而这里虽然是简化版的适用于安全从业者的基础知识,但也有小一万字,我写都这么痛苦了&#…

Linux入门教程

视频地址:http://study.163.com/course/courseMain.htm?courseId1002910005 命令帮助 使用命令man 使用命令的–help选项 使用infor命令 使用help命令查看内部命令 目录路径概念 非以根目录”/”表达的路径是相对路径 .表示当前目录,..表示当前…

linux操作系统和应用(完结)

目录大纲 此处大纲只做参考,如打不开,就手动移动位置。部分标题没有记录 linux系统 linux连接finallshell 开网卡连接到finallshelllinux安装yum命令和wget命令 linux命令 未分类命令开关机命令文档类[编辑文档等]文件层[文件/文件夹等]时间层查找类打包…

linux基础命令使用详解

网络篇 ping ping -c 3 -q -s 65500 -t 255 -i 0.1 -f www.baidu.com -c:指定ping的次数-q:只重结果不重过程-s: 默认情况下,ping命令是以64字节大小的数据包来测试网络联通性的,如需要改变默认数据包的大小,则可以使用参数-s选项。-t: 指…