cyber-guard has asked for the wisdom of the Perl Monks concerning the following question:

Hello Monks, I was having little fun figuring out different ways to do Rot13 encryption in perl, and I don't quite understand the behavior of the following script
#!/usr/bin/perl use 5.12.0; my @rot = qw(a v c g h t); @rot = map {$_++;eval;$_++} @rot; say @rot;
Firstly why the script fails to rotate the letters by one, if I remove either $_++ (I've tested several combinations with and operator, and that didn't work either)? Also that might be just me not fully understanding the implications of the eval string hack, but why won't $_++ for 1..13 or $_ += 13 work?

Btw I am aware of different and much easier ways to achieve rot13 encryption, but this is just little exercise...
Thanks for the answers.

Replies are listed 'Best First'.
Re: Rot13 encryption
by moritz (Cardinal) on Feb 06, 2011 at 18:50 UTC
    Firstly why the script fails to rotate the letters by one, if I remove either $_++ (I've tested several combinations with and operator, and that didn't work either)?

    $x++ returns $x, and increments $x in-place. So the first $_++ increments $_, and the the second instance of $_++ only has the function to return $_; the actual increment it does is lost. You can achieve the same thing with map { $_++; $_ }.

    Also that might be just me not fully understanding the implications of the eval string hack

    Afaict it does nothing (and I don't see any changed behavior if I remove it).

    Also note that your code turns z into aa, a feature not desired for rot13.

    but why won't $_++ for 1..13 or $_ += 13 work?

    $_++ for 1..13 doesn't work because foreach has its own $_ variable, which is set to the item it currently iterates over. Something like $x++ for 1..13 should work.

     $_ += 13 assumes numeric context, ie it lacks the magic that ++ possesses.

      Cheers, that pretty much answers everything. To the eval, I thought that in order to increment a string with ++, you had to eval it first; although I don't quite remember why that was...
Re: Rot13 encryption
by wind (Priest) on Feb 06, 2011 at 19:49 UTC

    As moritz already pointed out, this just relies on the way that the incrementer works on characters. Your code can be reduced a little further by using the preincrementor within the map, although it won't solve the problem with 'z' becoming 'aa'. But tighter still would be to just use a for:

    #!/usr/bin/perl use 5.12.0; my @rot = qw(a v c g h t); $_++ for @rot; say @rot;

    - Miller