做题学Python笔记(1)
前言:这次挑战了蓝桥云课程的编程实战赛“卷兔来袭”,学到了许多有意思的加密方式。大部分的题目要求都是不许调库,所以基本上都是在用条件和循环来解题,一些对字符串的基本操作得到了很好的复习。以下针对题目中卡壳的地方做一些笔记。
1. 破解藏头诗
题目的意思很简单,就是把每一句诗的第一个字提取出来连接成一句话。
- 先把诗句按照标点符号分割,再去掉句首的空格,然后取第一个字进行拼接
- 先按空格分割后拼接,再按照标点符号分割,取首字拼接
tip1:
比较常用的分割函数“split()”在一般情况下只能使用单一分隔符进行分割,如果要用到2种及以上的分隔符就需要导入re库:
text=“苦心人天不负, 卧薪尝胆, 三千越甲可吞吴。 有志者事竞成, 破釜沉舟, 百二秦川终属楚。”
out=text.split(sep,n) #sep为分隔符只能为一种,n也从左至右的分割次数
import re
text=re.split(sep,str,n) #sep为分隔符,str为需要分割的字符串,n为分割次数可省略
#eg:
text=re.split(",|。",text)
import re
def acrostic_poetry_decryption(poem: str) -> str:
"""TODO
"""
decryption_text : str = ''
#判断是否为空
if poem:
#判断是否为空格
if poem.isspace() is not True:
#判断是否为空字符串
if poem!='':
#去掉内部空格后按句分割
poem=poem.split()
poem=''.join(poem)
poem=re.split('[,。]', poem)
for i in poem:
if i!="":
decryption_text+=i[0]
continue
else:
decryption_text=None
else:
decryption_text=None
else:
decryption_text=None
return decryption_text
tip2
可以选择直接用"+"在for循环中将提取出来的字符粘贴起来,也可以使用列表先存储再用join函数
"sep".join(object) #sep为连接用的间隔符号,object为待连接的对象
tip3
“isspace()”用于判断字符串是否全为空格
判断字符串是否为None要用“is”
2. 破解曾公亮密码
查找输入字符在古诗中对应的位置索引,再去查找数字对应的短语。
- 有了第一个题目的经验这题就很好解了,先使用split分别去掉“,”“。”,再用join粘起来,对输入的字符进行判断(非None,非空,长度不超过1)之后用find查找其位置。
- . 用字典来存储这些短语,再进行查询。
def zeng_gongliang_decryption(text: str) -> str:
"""TODO
"""
key_dict = {'1':'请弓', '2':'请箭', '3':'请刀', '4':'请甲', '5':'请枪旗',
'6':'请锅幕', '7':'请马', '8':'请衣赐', '9':'请粮料', '10':'请草料',
'11':'请车牛', '12':'请船', '13':'请攻城守县', '14':'请添兵', '15':'请移营',
'16':'请进军', '17':'请退军', '18':'请固定', '19':'未见军', '20':'见贼',
'21':'贼多', '22':'贼少', '23':'贼相敌', '24':'贼添兵', '25':'贼移营',
'26':'贼进军', '27':'贼退军', '28':'贼固守', '29':'围得贼城', '30':'解围城',
'31':'被贼围', '32':'贼围解', '33':'战不胜', '34':'战大胜', '35':'战大捷',
'36':'将士投降', '37':'将士叛', '38':'士卒病', '39':'部将病', '40':'战小胜',}
decryption_text : str = ''
key="城阙辅三秦,风烟望五津。与君离别意,同是宦游人。海内存知己,天涯若比邻。无为在歧路,儿女共沾巾。"
key=''.join(key.split(','))
key=''.join(key.split('。'))
print(key)
if text is not None :
if text !='' :
if text.isspace() is not True:
if len(text)==1:
q=key.find(text)
decryption_text=key_dict[str(q+1)]
else:
decryption_text=None
else:
decryption_text=None
else:
decryption_text=None
else:
decryption_text=None
return decryption_text
3. 破解三角形密码
- 这题我的思路比较简单粗暴,先用for循环确定分几行,再通过每一行的区间定为最后一个字符,因为刚好从上至下的行数也就是有字区间的长度,这样就需要两个for循环。
def triangle_decryption(text: str) -> str:
"""TODO
"""
decryption_text : str = ''
try:
if text=='' or text.isspace():
decryption_text=None
return decryption_text
text=text.strip()
q=0
if len(text)<=2:
decryption_text=text
return decryption_text
else:
for i in range(len(text)):
if i*(i+1)/2 >=len(text):
q=i
break
p=0
for j in range(1,q+1):
if j!=q:
p+=j
decryption_text+=text[p-1]
else:
decryption_text+=text[-1]
return decryption_text
except:
decryption_text=None
return decryption_text
- 现在想来还有一种方法,直接在一个for循环中进行处理,处理到最后一行通过break直接跳出循环。
tip1:
这题有一个坑点,输入的可能不是字符串,我才用了try……except语句用来处理
4. 栅栏加密
如果分组字数不确定这个题目就要点难,但是确定了每组2个字那就比较容易了,直接用一个for循环,用两个list来分别存储没2字区间前面一个字和后面一个字,再用join()拼接起来即可
def fence_encryption(text: str) -> str:
"""TODO
"""
encryption_text : str = ''
if text=='':
encryption_text=None
elif text is None:
encryption_text=None
elif text.isspace():
encryption_text=None
else:
l1=''
l2=''
#去空格
text=''.join(text.split())
#分组
if len(text)%2==0:
for i in range(1,len(text),2):
l1+=text[i-1]
l2+=text[i]
text=l1+l2
encryption_text="".join(text)
else:
for j in range(0,len(text),2):
l1+=text[j]
if j<len(text)-1:
l2+=text[j+1]
else:
continue
text=l1+l2
encryption_text="".join(text)
return encryption_text
# text = '我爱他'
# print(fence_encryption(text))
tip1:
去空格的操作在前面也有提及
如果只是要去掉句首的空格可以使用text.strip()函数;
如果要去掉句中的所有空格可以通过split()先分开再join()连起来
5. 棋盘加密
感觉这题就是比较简单的找规律,将26个英文字母每五个一行的填充进去,字母序号除以5得到的商加上1就是行数,除出来的余数就是列数(余数为0的情况单独处理),就是i与j共用一个格子,需要分两部分来处理字母序号。
最后这题就是用了许多的if语句
def polybius_encryption(text: str) -> str:
"""TODO
"""
encryption_text : str = ''
#存储密码
key='abcdefghijklmnopqrstuvwxyz'
try:
if text is None:
encryption_text=None
else:
text=text.strip()
if text=='':
encryption_text=None
else:
text=''.join(text.split())
text=text.lower()
for i in list(text):
if key.find(i)!=-1:
if key.find(i)<9:
if (key.find(i)+1)%5!=0:
encryption_text+=str((key.find(i)+1)//5+1)
encryption_text+=str((key.find(i)+1)%5)
else:
encryption_text+=str((key.find(i)+1)//5)
encryption_text+='5'
else:
if (key.find(i))%5!=0:
encryption_text+=str((key.find(i))//5+1)
encryption_text+=str(key.find(i)%5)
else:
encryption_text+=str((key.find(i))//5)
encryption_text+='5'
else:
encryption_text+=i
except:
encryption_text=None
return encryption_text
tip1:
判断字符是否是属于字母区间的,有两种方法:
- 用ord()获得字母的ASCII码值,判断是否在65~ 90,97~122之间(后来想到的)
- 将小写字母按照顺序存在字符串里,先将输入的text用lower()函数全部变小写,再用find()函数查找索引,若返回值为-1则代表没找到
6. 姜子牙阴书加密
这题我的处理方法也比较简单粗暴,最后的输出达到了要求但是一直通不过,不知道是哪里有细节没考虑到。
- 在一个for循环里设置1个指针k用来记录每一个切片的起始位置,和一个记录累加区间长度的变量p
- 每循环一次完成一次切片
def yin_book_encryption(text: str) -> list:
"""TODO
"""
encryption_text : list = []
#k用来累加,p用来确定起始区间
k=0
p=0
if text is None:
encryption_text=None
return encryption_text
else:
if text=="" or text.isspace():
encryption_text=None
return encryption_text
else:
for i in range(1,len(text)):
if p>=len(text):
break
else:
k+=i
encryption_text.append(text[p:p+k])
p+=k
return encryption_text
# text=None
# print(yin_book_encryption(text))
7. 明码加密
这题考察的就是对字符串和整型之间的变化处理了。
输入的整数numb不足四位的前方补0:
numb=str("%04d"%numb)
def plain_code_encryption(numb: int) -> str:
"""TODO
"""
encryption_text : str = ''
key='9853'
if numb<0 or numb>9999:
encryption_text=None
return encryption_text
else:
if numb<1000:
numb=str("%04d"%numb)
else:
numb=str(numb)
for i in range(4):
if numb[i]==0:
i=10
encryption_text+=str((int(numb[i])+int(key[i]))%10)
else:
encryption_text+=str((int(numb[i])+int(key[i]))%10)
return encryption_text
# plain_code_encryption(12345)
其他的采用if语句即可,感觉后面越做越简单
8. 列置换加密
这题稍稍有点绕,但是逻辑理清楚了也很简单
- 先根据题目要求补齐,这里我才用的方法是直接在后面"+“上”,"
- 然后分行存储各个字符,采用for循环和二维列表来实现
- 理清逻辑之后直接置换对应的元素即可
def column_permutation_encryption(text: str) -> str:
"""TODO
"""
encryption_text : str = ''
if text is None:
encryption_text=None
return encryption_text
else:
if text == '':
encryption_text=None
return encryption_text
else:
#补齐操作
if len(text)%4 != 0:
text+=((4-len(text)%4)*',')
#分行
ls=[]
tran=[]
for i in range((len(text)+len(text)%4)//4):
ls.append(list(text[4*i:4*i+4]))
tran.append(list(text[4*i:4*i+4]))
#列置换
for k in range(len(ls)): #表示行数
tran[k][0]=ls[k][3]
tran[k][1]=ls[k][1]
tran[k][2]=ls[k][0]
tran[k][3]=ls[k][2]
print(tran)
for m in range(4):
for i in tran:
encryption_text+=i[m]
return encryption_text
tip1:
这里我遇到的一个问题是对列表的拷贝,简单的用“=”拷贝出来的列表修改会受到影响。copy()只能用来对一维的列表进行。要想对二维列表进行深层拷贝需要用到deepcopy(),由于这里不能导包我选择直接在开始就新建两个列表进行相同的处理。
具体的区别指路在Python中列表拷贝的五种方法
9. 凯撒加密
乍一想我是觉得可以用首位相连的链表来储存秘钥这样无论取多少位的偏移都可以很方便的查询,但这里给定了偏移位数为2就可以用比较简单粗暴的方法来解决。
def caesar_encryption(text: str) -> str:
"""TODO
"""
encryption_text : str = ''
#A~Z:65~90,a~z:97~122
try:
if text is None:
encryption_text=None
return encryption_text
else:
if text=='':
encryption_text=''
return encryption_text
else:
for i in list(text):
if 65<=ord(i)<=88 or 97<=ord(i)<=120:
encryption_text+=chr(ord(i)+2)
elif 88<ord(i)<=90 or 120<ord(i)<=122:
encryption_text+=chr(ord(i)-24)
else:
encryption_text+=i
return encryption_text
except:
encryption_text=None
return encryption_text
# text='xz'
# print(caesar_encryption(text))
10. 仿射加密
有点像哈希表?也是很简单粗暴
def affine_encryption(text: str) -> str:
"""TODO
"""
encryption_text : str = ''
if text is None:
encryption_text=None
return encryption_text
else:
if text == '':
encryption_text=None
return encryption_text
else:
if text.isspace():
encryption_text=text
return encryption_text
else:
for i in list(text):
if 65<=ord(i)<=90 or 97<=ord(i)<=122:
j=ord(i.lower())-97
q=(5*j+8)%26
encryption_text+=chr(q+97)
else:
encryption_text+=i
return encryption_text
以上内容仅为拙见,有更好的方法欢迎评论区交流。