在文本文件中用Python加密消息
我正在尝试读取一个文件,并使用我的函数对消息进行加密。我只想加密单词,其他的内容保持不变。我要读取的文件叫做 plain.txt,想把加密后的内容保存到一个新文件 newPlain.txt 中。此外,我还需要确定加密时的位移数量。
这是我的函数:
# k is how many shifts you want
def CaeserCipher(string, k):
upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
lower = 'abcdefgihjklmnopqrstuvwxyz'
newCipher = ''
for letter in string:
if letter in upper:
if upper.index(letter) + k > 25:
indexPosition = (upper.index(letter) + k) - 26
newCipher = newCipher + upper[indexPosition]
else:
indexPosition = upper.index(letter) + k
newCipher = newCipher + upper[indexPosition]
elif letter in lower:
if lower.index(letter) + k > 25:
indexPosition = (lower.index(letter) + k) - 26
newCipher = newCipher + lower[indexPosition]
else:
indexPosition = lower.index(letter) + k
newCipher = newCipher + lower[indexPosition]
return newCipher
这是我目前的进展:
# main file
# reading file and encrypting text
f = open('plain.txt', "r+")
for line in f:
newLine = CaeserCipher(line, 3)
line.replace(line, newLine)
f.close()
我是不是应该把内容分成一个列表?但如果这样做的话,我该怎么把它放回原来的位置呢?如果有人有好的想法,能告诉我该怎么做,我会非常感激。
plain.txt:(它不一定要以字母开头,也可以以空格或其他非字母的字符开头。)
你好,我的名字是 Ed。
你好吗?
来自 - Ed
2 个回答
你可以直接一个一个地处理每一行,只要在写的时候记得加上换行符就行。
with open('plain.txt','r+') as plainFile:
lines = plainFile.read().splitlines()
with open('newPlain.txt', 'w') as newFile:
for line in lines:
newFile.write(CaesarCipher(line, 3) + "\n")
这样就会依次处理每一行,给每一行加密,然后再把它们写出来。
如果我是你,我会把每个单词单独拿出来,然后把它们映射到 CaeserCipher
(正确的写法是 caesercipher
,根据 PEP-8 规范,类名应该用大写字母开头)。这样做的原因是你一开始提到的:“我只想加密单词,其他的都不动。”所以,做一些映射和过滤的操作听起来不错。
# def isWord(word):
# return all(ch.isalpha() for ch in word)
# oops I forgot that str.isalpha handles whole strings and not
# just characters. This is useless.
with open('plain.txt') as inf and open('encrypted.txt','w') as outf:
for line in inf:
line = [caesercipher(word) if word.isalpha() else word for word in line.strip().split()]]
outf.write(' '.join(line)+"\n")
另外,你可以重新定义你的 caesercipher
,让它不去处理那些不是单词的东西。
def caesercipher(string, k):
upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
lower = 'abcdefgihjklmnopqrstuvwxyz'
if not string.isalpha():
return string
else:
# apply your cipher, which honestly should be something using a deque
# rotation building a str.translate mapping, but we'll keep it simple
# for now. Let me know if you want more info on that though.
然后在我之前发的第一个代码块中,跳过你 line = [caesercipher(word) ...
这行代码里的检查。
可选:双端队列替代方案
deque
基本上就是一个循环列表。你可以用 rotate
方法来旋转它,比如 deque(['1','2','3']).rotate(1) == deque(['3','1','2'])
。你可以用这个来构建一个非常高效的凯撒密码,像这样:
from collections import deque
from copy import copy # just to save time
def caesercipher(string, k):
upper = deque("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
lower = deque("abcdefghijklmnopqrstuvwxyz")
resultupper = copy(upper)
resultupper.rotate(-k)
resultlower = copy(lower)
resultlower.rotate(-k)
dict_for_trans = dict(zip(upper,resultupper))
dict_for_trans.update(dict(zip(lower,resultlower)))
transdict = str.maketrans(dict_for_trans)
return string.translate(transdict)
这个方法的好处是 str.translate
非常快,而你提供的字典确保只有你自己定义的内容会被处理。没有那些耗时的 list.index
调用,一切都是快速处理的。这个方法还很实用,因为当 k > 26
时,它依然有效!比如 caesercipher("abc",27) -> 'bcd'