1
\$\begingroup\$

I have written a simple Caesar Cipher in Python in my efforts to learn a language that isn't C. It works much like any other Caesar implementation and takes various command line arguments to specify options such as the spacing of the output, whether to encrypt or decrypt the input, and whether or not to try and bruteforce the cipher.

This is my first ever Python program so I'm primarily looking to learn some best practices for the language as well as remove any inefficiencies or redundancies in my code.

Thanks!

import argparse
import re

def caesar(string, shift):
    output = ''
    for char in string:
        if char.isspace():
            output += ' '
        else:
            output += chr(((ord(char) - 65 + shift) % 26) + 65)
    return output

def main():
    parser = argparse.ArgumentParser(description = "Encrypt or decrpyt a string using the Caesar Cipher")

    parser.add_argument("--bruteforce", "--brute", "-b", help = "bruteforce mode", action = "store_true")
    parser.add_argument("--encrypt", "--enc", "-e", help = "encryption mode (default)", action = "store_true")
    parser.add_argument("--decrpyt", "--dec", "-d", help = "decryption mode", action = "store_true")
    parser.add_argument("--no-spacing", "--no-space", "-n", help = "no spacing in output (default)", action = "store_true")
    parser.add_argument("--preserve-spacing", "--preserve", "-p", help = "use same spacing as original string", action = "store_true")
    parser.add_argument("--shift", "-s", help = "value for the Caesar shift", type = int, choices = range(1, 26))
    parser.add_argument("--spacing", "-x", help = "specify the spacing in output", type = int)

    args = parser.parse_args()

    if args.bruteforce:
        bruteforce = True
    else:
        bruteforce = False
        shift = args.shift

    if args.decrpyt:
        shift = -shift

    if args.preserve_spacing: 
        regex = re.compile('[^A-Z\s]')
    else:
        regex = re.compile('[^A-Z]')

    string = regex.sub('', input().upper())

    if args.spacing:
        string = ' '.join([string[i:i + args.spacing] for i in range(0, len(string), args.spacing)])

    if bruteforce:
        for shift in range(1, 26):
            print("%d: %s" %(shift, caesar(string, -shift)))
    else:
        print(caesar(string, shift))

if __name__ == "__main__":
    main()
\$\endgroup\$
1
\$\begingroup\$

The Caesar function

First the parameter string should be renamed as it has the same name as the standard module string. Sure you don't use it, but it is a bad habit to get into and can result in problems later on. Regardless, since we're dealing with cryptography and sending messages and such, wouldn't a better word be message?

There is also no documentation. caesar is not a descriptive name if you don't already know what a Caesar cipher is. You should have a docstring that describes that this a Caesar cipher and at least link to Wikipedia for a description of the Caesar cipher if not describe it yourself.

The main function

store_true

if args.bruteforce:
    bruteforce = True
else:
    bruteforce = False
    shift = args.shift

The 'store_true' flag indicates that args.bruteforce is True when the flag is specified and False when it is not specified. Forget the bruteforce variable and just concern yourself with args.bruteforce.

store_const

There is also a store_const action that has the optional1 parameters const and default. Thus you can have const=re.compile('[^A-Z\s]') and default=re.compile('[^A-Z]'). This removes the need for:

if args.preserve_spacing: 
    regex = re.compile('[^A-Z\s]')
else:
    regex = re.compile('[^A-Z]')

1 The const parameter is a paradoxically optional argument that is required

\$\endgroup\$
  • \$\begingroup\$ Thanks for this, could you expand a bit on the last part? What is a store_const action? \$\endgroup\$ – psychedelic_alex Sep 4 '18 at 6:08
  • \$\begingroup\$ @psychedelic_alex The store_const is a generalization of store_true and store_false. When the flag (args.flag) is supplied store_const will give args.flag the value of the "optional" parameter const and if the flag is not supplied it will be either None or the value of the optional parameter default. To illustrate store_true is equivalent to store_const with const=True and default=False. \$\endgroup\$ – Dair Sep 4 '18 at 6:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.