2

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

2 Answers 2

2

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'

Sign up to request clarification or add additional context in comments.

1 Comment

Also as a side note, if you import string and change the name of your parameter in caesercipher(string, k), you can do upper = string.ascii_uppercase and lower = string.ascii_lowercase.
1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.