Caveat
The Caesar cipher encrypts text by rotating the alphabet, leaving digits and symbols unchanged. It was used in ancient times to encrypt confidential messages, but from today's perspective it is just a toy cipher.
The purpose of this article is not to promote the Caesar cipher, but to demonstrate how to use C++'s features in its implementation for the English language.
Goal
- To provide a means to encrypt
char[]
's, std::string
s, and files.
- It is achieved by a function template which works with iterators.
Language
C++11, the 2011 version of the C++ language's standard.
Your C++ compiler must support lambda functions, range-based
for()
loops, and initializer lists, for to successfully compile the source code snippets in this article, and the full program attached.
Parameters and design rationale
The core function of the program is named
caesar_cipher()
and it has four parameters:
Name |
Description |
src_begin |
source's beginning iterator |
src_end |
source's end iterator |
dest_begin |
destination's beginning iterator |
shift |
integer representing the alphabet shift |
The approach of passing iterators instead of an actual container has two advantages:
- The function is container-agnostic.
- The function's implementation is simplified.
Usage examples
- The Good
1 2 3 4
|
std::string s("Hello, World!");
caesar_cipher(s.begin(), s.end(), s.begin(), 4); // s == "Lipps, Asvph!"
caesar_cipher(s.begin(), s.end(), s.begin(), -4); // s == "Hello, World!"
| |
- The Bad
1 2 3 4 5
|
const std::vector<char> vc{'D', 'b', 'f', 't', 'b', 's'};
std::list<char> lc(vc.size());
caesar_cipher(vc.begin(), vc.end(), lc.begin(), -1);
// lc == std::list<char>({'C', 'a', 'e', 's', 'a', 'r'})
| |
- The Ugly
1 2 3 4 5
|
const char ca[]{"Sqjzanxwn!"};
std::unique_ptr<char[]> upca(new char[sizeof ca]);
caesar_cipher(std::begin(ca), std::end(ca), upca.get(), 4);
// std::strcmp(upca.get(), "Wunderbar!") == 0
| |
Core function source code
If you need the full program, that works with files, skip to the next section.
Notes:
- When the alphabet shifts, it wraps. This means that for an alphabet with a length of 26, a shift of 27 will be the same as a shift of 1, and a shift of 52 will be the same as no shift at all.
- The purpose of line 11 is to trim
shift
to a value that can be used in std::rotate()
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
|
#include <algorithm>
#include <cctype>
#include <string>
template <typename InputIterator, typename OutputIterator>
OutputIterator caesar_cipher(InputIterator src_begin, InputIterator src_end, OutputIterator dest_begin, int shift)
{
const std::string ab("abcdefghijklmnopqrstuvwxyz"); // AlphaBet
std::string rot_ab(ab); // ROTated AlphaBet
shift %= static_cast<int> (ab.length());
if (shift < 0)
std::rotate(rot_ab.rbegin(), rot_ab.rbegin() - shift, rot_ab.rend());
else
std::rotate(rot_ab.begin(), rot_ab.begin() + shift, rot_ab.end());
return std::transform(src_begin, src_end, dest_begin, [ab, rot_ab](unsigned char c) -> char {
if (std::isalpha(c))
{
if (std::isupper(c))
return std::toupper(rot_ab.at(ab.find(std::tolower(c))));
return rot_ab.at(ab.find(c));
}
return c;
});
}
| |
Full program source code
Please download the ZIP archive attachment at the end of the article.
Useful links
Thanks go to
Attachments:
[caesar.zip]