http://www.perlmonks.org?node_id=1047816

Iggyroo2000 has asked for the wisdom of the Perl Monks concerning the following question:

I'm new to using perl, but I've been instructed to create a Caesar Cipher to decode a sentence. From what I've heard is that there is a function in perl that allows you to create a Caesar cipher. I'm not quite sure where to find information on how to use the function or what is required to use the function. I know its a 10 shift to the right...can someone help me figure out where to start. Please know I'm very new, so please try to explain what the different steps are for. Thanks

Replies are listed 'Best First'.
Re: Caesar Cipher
by moritz (Cardinal) on Aug 04, 2013 at 19:43 UTC

    a Caesar Cipher just substitutes each character for a fixed replacement. The easiest way to do that in Perl is with the tr operator:

    use 5.010; use warnings; my $original = lc "Ceterum censeo Carthaginem esse delendam"; my $cyphered = $original; $cyphered =~ tr/a-z/k-za-j/; say $cyphered; my $decyphered = $cyphered; $decyphered =~ tr/k-za-j/a-z/; say $decyphered;
Re: Caesar Cipher
by kcott (Archbishop) on Aug 05, 2013 at 07:01 UTC

    G'day Iggyroo2000,

    Welcome to the monastery.

    "I'm new to using perl, but I've been instructed to create a Caesar Cipher to decode a sentence. From what I've heard is that there is a function in perl that allows you to create a Caesar cipher."

    That seems somewhat vague with respect to what you're actually trying to achieve. I'm unsure whether you have data you wish to encrypt, decrypt or both. Plugging "Caesar Cipher" into your favourite search engine should produce pages of results: perhaps a little (more) research will help clarify what you're really after.

    There's no caesar_cipher() function, as such, in Perl. There are some CPAN modules that may do what you want. A quick search found Text::Cipher::KeywordAlphabet and Crypt::Caesar: I leave you to look for others.

    "I know its a 10 shift to the right."

    I agree with what ww said about this (above), i.e. the shift amount is arbitrary and can be either left or right. Perhaps you meant that in your specific case that's what you have to deal with.

    Anyway, your post piqued my interest and I wrote a short script that both encrypts and decrypts, shifting an arbitrary amount either left or right (using all printable ASCII characters: ' ' [space: chr(32)] to '~' [tilde: chr(126)]). It's actually fairly straightforward but, as you've said how "very new" you are to Perl, I'll provide some documentation links at the end. The commandline interface is fairly clunky: if you use this script, you'll probably want to spend some time on improving that.

    #!/usr/bin/env perl -l use strict; use warnings; if (@ARGV != 4) { print "Usage: $0 text encrypt/decrypt(1|0) ", 'right_shift/left_shift(1|0) positions_to_shift'; print "(Note: when decrypting, '*_shift' and 'positions_to_shift' +", 'is what was used for the original encryption!)'; exit; } my @chars = map { "\Q@{[chr]}\E" } 32 .. 126; my ($input, $encrypt, $right, $pos) = @ARGV; $pos %= @chars; my $plain_chars = join '' => @chars; my $cipher_chars = $right ? join('' => @chars[$pos .. $#chars, 0 .. $pos - 1]) : join('' => @chars[$#chars - $pos + 1 .. $#chars, 0 .. $#chars - +$pos]); print 'Transform: ', ($encrypt ? 'encrypt' : 'decrypt'), ' -- Shift: ', ($right ? 'right' : 'left'), ' -- Positions: ', $pos; if ($encrypt) { my $ciphertext; eval "(\$ciphertext = \$input) =~ y/$plain_chars/$cipher_chars/"; print "Plaintext: $input"; print "Ciphertext: $ciphertext"; } else { my $plaintext; eval "(\$plaintext = \$input) =~ y/$cipher_chars/$plain_chars/"; print "Ciphertext: $input"; print "Plaintext: $plaintext"; }

    Documentation you may find useful:

    Here's a few sample runs:

    $ pm_caesar_cipher.pl def 1 1 3 Transform: encrypt -- Shift: right -- Positions: 3 Plaintext: def Ciphertext: ghi
    $ pm_caesar_cipher.pl ghi 0 1 3 Transform: decrypt -- Shift: right -- Positions: 3 Ciphertext: ghi Plaintext: def
    $ pm_caesar_cipher.pl def 1 0 3 Transform: encrypt -- Shift: left -- Positions: 3 Plaintext: def Ciphertext: abc
    $ pm_caesar_cipher.pl abc 0 0 3 Transform: decrypt -- Shift: left -- Positions: 3 Ciphertext: abc Plaintext: def
    $ pm_caesar_cipher.pl 'The quick brown fox jumped over the lazy dog.' +1 1 145 Transform: encrypt -- Shift: right -- Positions: 50 Plaintext: The quick brown fox jumped over the lazy dog. Ciphertext: ';8RDH<6>R5EBJAR9BKR=H@C87RBI8ERG;8R?4MLR7B:`
    $ pm_caesar_cipher.pl "';8RDH<6>R5EBJAR9BKR=H@C87RBI8ERG;8R?4MLR7B:\`" + 0 1 145 Transform: decrypt -- Shift: right -- Positions: 50 Ciphertext: ';8RDH<6>R5EBJAR9BKR=H@C87RBI8ERG;8R?4MLR7B:` Plaintext: The quick brown fox jumped over the lazy dog.
    $ pm_caesar_cipher.pl Usage: ./pm_caesar_cipher.pl text encrypt/decrypt(1|0) right_shift/lef +t_shift(1|0) positions_to_shift (Note: when decrypting, '*_shift' and 'positions_to_shift' is what was + used for the original encryption!)

    -- Ken

Re: Caesar Cipher
by ww (Archbishop) on Aug 04, 2013 at 20:48 UTC
    Historians sometimes assert that any "encoding system" using a fixed value for the change in positions in the alphabet is a (n example of a) Ceasar Cipher -- ie, if the value for the change is +3, A (in position 1) becomes D (position 4). 13 is the oft-cited value.

    In the computer world, it's often called ROT13 for rotate 13 positions. moritz' example above provides an example.

    I don't know about a "10 shift to the right" -- certainly, as indicated in para 1, that would be a valid way to implementing a Ceasar Cipher... and so would a 10 shift to the left but (IMO) both would make it easier to err if "encoding" manually.

    If I've misconstrued your question or the logic needed to answer it, I offer my apologies to all those electrons which were inconvenienced by the creation of this post.
      I don't know about a "10 shift to the right" ...

      Actually, moritz's example is of a 10-position shift, a-j being the first ten letters of the (English) alphabet. Not that it really matters.

Re: Caesar Cipher
by marinersk (Priest) on Aug 05, 2013 at 15:58 UTC
    The tr approach is probably the most Perl-True approach for a one-off script to perform the cipher with a given (i.e., hard coded) shift.

    However, since this smells like like a homework assignment, and you are new to Perl, I would be inclined to suggest something a little more generic -- use an array.

    It would be slower, but since you would be building the underlying mechanisms, you would understand its workings more thoroughly.

    I know you are essentially asking for theoretical guidance, but have you done any work on this so far? Like, for example, the code which collects the text to be so ciphered?

    For example -- intentionally silly:

    #!/usr/bin/perl use strict; { foreach my $inputString (@inputArray) { my $cipheredText = &ceaser_cipher($inputString); print "'$inputString' becomes '$cipheredText'\n"; } } exit; sub cipheredText { my ($rawText, @otherParameters) = @_; # The magic happens here -- have entered a SoPW request at PerlMo +nks. } __END__