Skip to content

Commit 48a598a

Browse files
authored
Refactor Caesar cipher functions and improve docstrings
1 parent e0b2a1f commit 48a598a

File tree

1 file changed

+71
-91
lines changed

1 file changed

+71
-91
lines changed

ciphers/caesar_cipher.py

Lines changed: 71 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,110 +1,90 @@
1-
from __future__ import annotations
2-
from string import ascii_letters
1+
"""
2+
Caesar Cipher Algorithm
33
4+
The Caesar cipher is one of the simplest and most widely known encryption techniques.
5+
It works by shifting each letter in the plaintext by a fixed number of positions
6+
down or up the alphabet.
47
5-
def encrypt(input_string: str, key: int, alphabet: str | None = None) -> str:
8+
Example:
9+
>>> encrypt("abc", 2)
10+
'cde'
11+
>>> decrypt("cde", 2)
12+
'abc'
13+
14+
You can also encrypt/decrypt with uppercase letters:
15+
>>> encrypt("Hello, World!", 3)
16+
'Khoor, Zruog!'
17+
>>> decrypt("Khoor, Zruog!", 3)
18+
'Hello, World!'
19+
20+
Reference:
21+
https://en.wikipedia.org/wiki/Caesar_cipher
22+
"""
23+
24+
from string import ascii_lowercase, ascii_uppercase
25+
26+
27+
def encrypt(text: str, shift: int) -> str:
628
"""
7-
Encrypts a given string with the Caesar cipher and returns the encoded message.
8-
9-
Parameters
10-
----------
11-
input_string : str
12-
The plain-text that needs to be encoded.
13-
key : int
14-
The number of letters to shift the message by.
15-
alphabet : str | None, optional
16-
The alphabet used to encode the cipher.
17-
If not specified, the standard English alphabet (a-z, A-Z) is used.
18-
19-
Returns
20-
-------
21-
str
22-
A string containing the encoded cipher-text.
23-
24-
Raises
25-
------
26-
TypeError
27-
If input_string is not a string or key is not an integer.
28-
29-
Examples
30-
--------
31-
>>> encrypt('The quick brown fox jumps over the lazy dog', 8)
32-
'Bpm yCqks jzwEv nwF rCuxA wDmz Bpm tiHG lwo'
33-
>>> encrypt('a lowercase alphabet', 5, 'abcdefghijklmnopqrstuvwxyz')
34-
'f qtbjwhfxj fqumfgjy'
29+
Encrypt the given text using Caesar cipher.
30+
31+
Args:
32+
text: The input text to encrypt.
33+
shift: The number of positions to shift each letter.
34+
35+
Returns:
36+
The encrypted text as a string.
37+
38+
>>> encrypt("abc", 1)
39+
'bcd'
40+
>>> encrypt("xyz", 3)
41+
'abc'
42+
>>> encrypt("Hello, World!", 5)
43+
'Mjqqt, Btwqi!'
3544
"""
36-
if not isinstance(input_string, str):
37-
raise TypeError("input_string must be a string.")
38-
if not isinstance(key, int):
39-
raise TypeError("key must be an integer.")
45+
if not isinstance(text, str):
46+
raise TypeError("Text must be a string.")
47+
if not isinstance(shift, int):
48+
raise TypeError("Shift must be an integer.")
4049

41-
alpha = alphabet or ascii_letters
4250
result = []
4351

44-
for character in input_string:
45-
if character not in alpha:
46-
result.append(character)
52+
for char in text:
53+
if char in ascii_lowercase:
54+
index = (ascii_lowercase.index(char) + shift) % 26
55+
result.append(ascii_lowercase[index])
56+
elif char in ascii_uppercase:
57+
index = (ascii_uppercase.index(char) + shift) % 26
58+
result.append(ascii_uppercase[index])
4759
else:
48-
new_index = (alpha.index(character) + key) % len(alpha)
49-
result.append(alpha[new_index])
60+
result.append(char)
5061

5162
return "".join(result)
5263

5364

54-
def decrypt(input_string: str, key: int, alphabet: str | None = None) -> str:
55-
"""
56-
Decodes a Caesar cipher text using the provided key.
57-
58-
Parameters
59-
----------
60-
input_string : str
61-
The cipher-text that needs to be decoded.
62-
key : int
63-
The number of letters to shift backward.
64-
alphabet : str | None, optional
65-
The alphabet used to decode the cipher.
66-
67-
Returns
68-
-------
69-
str
70-
The decoded plain-text.
71-
72-
Examples
73-
--------
74-
>>> decrypt('Bpm yCqks jzwEv nwF rCuxA wDmz Bpm tiHG lwo', 8)
75-
'The quick brown fox jumps over the lazy dog'
65+
def decrypt(text: str, shift: int) -> str:
7666
"""
77-
return encrypt(input_string, -key, alphabet)
67+
Decrypt the given text encrypted with Caesar cipher.
7868
69+
Args:
70+
text: The encrypted text to decrypt.
71+
shift: The number of positions originally used to encrypt.
7972
80-
def brute_force(input_string: str, alphabet: str | None = None) -> dict[int, str]:
81-
"""
82-
Attempts to brute-force all possible Caesar cipher keys.
83-
84-
Parameters
85-
----------
86-
input_string : str
87-
The cipher-text to attempt decoding.
88-
alphabet : str | None, optional
89-
The alphabet used to decode the cipher.
90-
91-
Returns
92-
-------
93-
dict[int, str]
94-
A dictionary mapping each key to its decoded message.
95-
96-
Examples
97-
--------
98-
>>> brute_force("jFyuMy xIH'N vLONy zILwy Gy!")[20]
99-
"Please don't brute force me!"
73+
Returns:
74+
The decrypted text as a string.
75+
76+
>>> decrypt("bcd", 1)
77+
'abc'
78+
>>> decrypt("abc", 3)
79+
'xyz'
80+
>>> decrypt("Mjqqt, Btwqi!", 5)
81+
'Hello, World!'
10082
"""
101-
if not isinstance(input_string, str):
102-
raise TypeError("input_string must be a string.")
83+
return encrypt(text, -shift)
10384

104-
alpha = alphabet or ascii_letters
105-
results = {}
10685

107-
for key in range(1, len(alpha) + 1):
108-
results[key] = decrypt(input_string, key, alpha)
86+
if __name__ == "__main__":
87+
import doctest
10988

110-
return results
89+
doctest.testmod()
90+
print("✅ All doctests passed!")

0 commit comments

Comments
 (0)