user3491255
user3491255

Reputation: 163

encrypting message in a text file python

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

Answers (2)

Adam Smith
Adam Smith

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

Seth
Seth

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

Related Questions