在文本文件中用Python加密消息

2 投票
2 回答
1630 浏览
提问于 2025-04-18 03:01

我正在尝试读取一个文件,并使用我的函数对消息进行加密。我只想加密单词,其他的内容保持不变。我要读取的文件叫做 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 个回答

1

你可以直接一个一个地处理每一行,只要在写的时候记得加上换行符就行。

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")

这样就会依次处理每一行,给每一行加密,然后再把它们写出来。

2

如果我是你,我会把每个单词单独拿出来,然后把它们映射到 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'

撰写回答