Implementing a Caesar Cipher
00:00 The Caesar cipher is an encryption technique named after the Roman general Julius Caesar, who reportedly used it to encrypt military messages. The cipher is pretty straightforward.
00:13 The idea is that all of the letters of the alphabet are shifted by some fixed amount. So for example, if we’re going to be shifting all letters by 4, we take the standard alphabet in the natural order and then the letter A, if we shift by 4 becomes the letter E, B becomes the letter F, C becomes G, and so on.
00:39 When we get to W, we have to then wrap around the alphabet, so W becomes A, X becomes B, and then Y and Z become C and D.
00:51 If a character in the string is not part of the alphabet, then we don’t transform it and we just leave it as it is—so, things like punctuation, whitespace, and other non-alphabet characters.
01:04 If you think about what this is going to be doing to a string, which is an iterable, we’re going to be mapping this function that takes A to E, B to F, C to G, and so on at each character of the string.
01:18 So again, we have this idea of wanting to map a function at every element of an iterable to return a new transformed iterable. All right, let’s write this up and give it a try.
01:32
Before we go ahead and write the cipher, we’re going to be using a module called the string
module, which contains as one long string all of the letters of the alphabet in lowercase.
01:44
We’re going to import from the string
module, we’re going to import all of the ASCII lowercase characters, and we’re going to import this and call it the alphabet
, and I’ll show you in a second what the alphabet
is going to be.
02:00
So go ahead and type alphabet
, and the alphabet
just contains all of the lowercase letters of the alphabet. We’re going to use that in our cipher, and you could import this right into the function. That way, if you send this function to somebody else, it’s all self-contained.
02:17 But in this case, we’ll just import it like this.
02:22
All right, so now let’s go ahead and define the cipher. We’ll call it caesar()
, so Caesar cipher, and it’s going to take just a character, let’s say c
.
02:32 And we’re going to define in the function the amount that we want to shift by. Now, this may be a parameter that instead you want to pass into the function, but just for illustration purposes, let’s just define it right in the function.
02:46
So let’s just say we want to shift by 3
. Now, because we’re only interested in the lowercase characters, we want to make sure that if the message comes in with uppercase letters, we want to first convert the input character into lowercase, so we’ll call the .lower()
method in the str
class.
03:06
And then the first thing that we’ll do is check to see if the character is not in the alphabet
, and if it’s not, then we just want to simply return the character.
03:18 So any type of punctuation or non-alphabet characters, we just want to simply return them.
03:24
The first thing that we want to do is find the index of the character in the alphabet
, so we’ll call the .index()
method on the alphabet
string.
03:37
This is going to be an integer between 0
and 25
. The alphabet
is a string object, which is an iterable, and the index starts at 0
and the number of letters in the alphabet
is 26
, so this will be an integer from 0
to 25
.
03:51
Then we need to shift the index by the shift amount. This might take us over 25
, and so what we need to do is use the modulo operator (%
) so that we get the wrapping done correctly.
04:08
The number of letters in the alphabet is 26 and we can just hard-code that in, but maybe to make it a little bit more programmatic, we’ll just call the len()
(length) function on the alphabet
. That way, if you are using a different alphabet, you’re not hard-coding in 26
and you’re just using the length of the alphabet
that you’re using.
04:27
So, why don’t we call this, say, the shifted index or idx_shift
,
04:34 and then we simply want to return the character, or the letter, in the alphabet that corresponds to the shifted index. Go ahead and run that. And why don’t we give this a try?
04:48
So, for example, if we take the letter 'a'
and we’re shifting it by 3
, that’ll give us 'd'
. If we shift the letter 'b'
, that should give us 'e'
. Now, the letter 'x'
is going to be the first letter that wraps around the alphabet, so 'x'
will get mapped to 'a'
, and 'y'
to 'b'
, and then 'z'
to 'c'
. All right, so why don’t we give this a try with a string?
05:19
Let’s clear that out and let’s map our Caesar cipher to an iterable, which is going to be a string, and maybe this is the secret message that we want to encode and so why don’t we write "My secret message goes here"
. And we know we’re going to get an iterator.
05:39
And why don’t we just go ahead and save this as, say, the secret
.
05:45
Now let’s see what the secret
is after the encryption. Remember that the secret
variable is an iterator—it’s going to return each encrypted character one at a time.
05:54
So if we want to see this as a string, let’s join the elements that are returned by the secret
iterator with an empty string. And this’ll be okay because remember, the blank spaces in the original string are kept intact, so we’ll have the whitespaces already built in to the encrypted string.
06:15
This seems to be working. For example, the letter 'm'
if we shift it by 3 characters, the lowercase letter 'm'
, we’re going to get 'n'
, 'o'
, 'p'
.
06:27
And the letter 'y'
if we shift it by 3 characters, we’re going to get 'z'
, 'a'
, 'b'
. And so that seems to be working well.
06:36 All right! So this is, again, another good example of this general idea of wanting to map a function at every element of an iterable to return a new iterable that yields the transformed characters.
06:52
All right, this wraps up the lesson. In the next lesson and the one after that, we’re going to take a look at how we can combine the map()
function with two other important functions in functional programming.
Bartosz Zaczyński RP Team on Dec. 5, 2023
@Erick Kendall The percent sign (%
) is the modulo operator in Python, which can be handy in modular arithmetic.
In this case, it ensures that the shifted numbers will wrap around so that letters at the end of the alphabet, such as x, y, and z, will become a, b, and c, respectively:
>>> from string import ascii_lowercase as alphabet
>>> alphabet[(alphabet.index("z") + 3) % len(alphabet)]
'c'
When you don’t use the modulo operator, then letters at the end of the alphabet will cause an error because the corresponding ordinal values will exceed the bounds of your alphabet:
>>> alphabet[(alphabet.index("z") + 3)]
Traceback (most recent call last):
...
IndexError: string index out of range
Here are the underlying indices that you obtain with and without the modulo operator:
>>> (alphabet.index("z") + 3) % len(alphabet) # We're back at 2
2
>>> (alphabet.index("z") + 3) # That's too large!
28
>>> len(alphabet) # There are only 26 letters in the alphabet
26
Become a Member to join the conversation.
Erick Kendall on Dec. 5, 2023
I’m not clear on why we need to do
% len(alphabet)
.