Reputation: 163
I'm trying to read through a file and encrypt the message using my function. I want to only encrypt words and leave everything else alone. The file reading through is called plain.txt and I want to encrypt it in a new file called newPlain.txt. Also I need to justify how many shifts the cipher wants.
Here is my function:
# 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
this is what I have so far:
# 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()
Would I want to break it up into a list? But then if so, how would I be able to put it back into the same spot? If anyone has some ideas of how to go about this it would be greatly appreciated.
plain.txt: (it doesn't have to start with a alpha character, could start with a space too, or anything that isn't a letter.
Hello, My name is Ed.
How are you?
from- Ed
Upvotes: 2
Views: 1649
Reputation: 54163
If I were you, I would grab individual words and map them to CaeserCipher
(properly named caesercipher
, only use CapWords
for a Class as per PEP-8). The reason for this is one of your first bits: "I want to only encrypt words and leave everything else alone." Because of this, a little map/filter action sounds good.
# 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")
Alternatively, you can redefine your caesercipher
so it doesn't touch non-word words.
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.
And then skip the check in your line = [caesercipher(word) ...
statement in the first code block I posted.
OPTIONAL: DEQUE REPLACEMENT
a deque
is basically a circular list. You can rotate
it so deque(['1','2','3']).rotate(1) == deque(['3','1','2'])
. You can use this to build a pretty damn efficient Caeser cipher like so:
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)
The nice thing about this method is that str.translate
is very very fast, and the dictionary you provide it ensures that nothing EXCEPT what you personally define will be touched. None of these list.index
calls that take forever, everything is hashed and done quickly. It's also useful because for k > 26
, it still works! caesercipher("abc",27) -> 'bcd'
Upvotes: 2
Reputation: 21
You can just iterate over the lines, just make sure to append a newline when you write them.
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")
Which will iterate through the lines, encrypt the lines, and then write them, all sequentially.
Upvotes: 1