I'd like feedback on my solution to the outlined programming challenge (medium level). I've tried it fast in any way I know how to, but, what might be a more efficient and/or pythonic solution?
[Caesar Cipher] Using the Python language, have the function CaesarCipher(str,num) take the str parameter and perform a Caesar Cipher shift on it using the num parameter as the shifting number. A Caesar Cipher works by shifting each letter in the string N places down in the alphabet (in this case N will be num). Punctuation, spaces, and capitalization should remain intact. For example if the string is "Caesar Cipher" and num is 2 the output should be "Ecguct Ekrjgt".
import doctest
import logging
import timeit
from string import ascii_lowercase, ascii_uppercase
logging.basicConfig(
level=logging.DEBUG,
format="%(asctime)s - %(levelname)s - %(message)s")
# logging.disable(logging.CRITICAL)
ALPHABET_LENGTH = 26
# Wrap alphabet letters
LOWERCASE = ascii_lowercase + ascii_lowercase
UPPERCASE = ascii_uppercase + ascii_uppercase
def encode_string(s: str, n: int) -> str:
"""Perform a Caesar Cipher shift on s leaving punctuation, spaces intact
:param s: the str on which to perform a Cipher shift
:type s: str
:param n: the number of places in the alphabet to shift the letter.
Positive for a forward shift, negative for a backwards shift
:type n: int
>>> encode_string(s="Caesar Cipher", n=2)
'Ecguct Ekrjgt'
>>> encode_string(s="Caesar Cipher", n=54)
'Ecguct Ekrjgt'
>>> encode_string(s="Aa Bb", n=0)
'Aa Bb'
>>> encode_string(s="Cc Dd", n=-28)
'Aa Bb'
"""
if n ==0:
return s
# Incase of very large n, find lowest equivalent offset
n = n % ALPHABET_LENGTH
# value of n used to index constants, equivalent to -n steps in backwards direction
if n < 0:
n = ALPHABET_LENGTH - n
new_str = ""
for c in s:
if c in LOWERCASE:
i = LOWERCASE.index(c)
encoded_char = LOWERCASE[i + n]
new_str = new_str + encoded_char
elif c in UPPERCASE:
i = UPPERCASE.index(c)
encoded_char = UPPERCASE[i + n]
new_str = new_str + encoded_char
else:
new_str = new_str + c
return new_str
if __name__ == "__main__":
doctest.testmod()
print(timeit.timeit(
"encode_string(s='Caesar Cipher', n=2)",
setup="from __main__ import encode_string, ALPHABET_LENGTH, LOWERCASE, UPPERCASE",
number=100000)
)