Monday, April 11, 2011

Where is my one-line implementation of rot13 in JavaScript going wrong?

Code in question with syntax highlighting here: via Friendpaste

rot13.js:

<script>
String.prototype.rot13 = rot13 = function(s)
 {
    return (s = (s) ? s : this).split('').map(function(_)
     {
     if (!_.match(/[A-Za-z]/)) return _;
     c = Math.floor(_.charCodeAt(0) / 97);
     k = (_.toLowerCase().charCodeAt(0) - 96) % 26 + 13;
     return String.fromCharCode(k + ((c == 0) ? 64 : 96));
     }).join('');
 };
</script>

As you can see, using quite literally a single line to attach a method to the String object a la prototyping, I'm having a map() method that I previously set up (I know for sure that that code works perfectly; it's simply iterating over each element in the array and applying the function specified in the parameter) go over each character in a string and do what I thought were the proper calculations to transform the string into it's rot13'd counterpart. I was sadly mistaken. Can anybody spot where I went wrong?

From stackoverflow
  • should the % 26 come after the + 13?

    k = ((_.toLowerCase().charCodeAt(0) - 96) + 13) % 26;
    
    Hexagon Theory : Erm... swapping them around doesn't change anything...
    Sparr : this change definitely fixes part of the problem
  • javascript:String.prototype.rot13 = rot13 = function(s)
    {
      return (s = (s) ? s : this).split('').map(function(_)
      {
        if (!_.match(/[A-Za-z]/)) return _;
        c = _.charCodeAt(0)>=96;
        k = (_.toLowerCase().charCodeAt(0) - 96 + 12) % 26 + 1;
        return String.fromCharCode(k + (c ? 96 : 64));
      }
      ).join('');
    };
    
    alert('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.rot13());
    yields nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM
    

    Mixing zero-based and one-based indices for the lose. I blame Netscape.

  • You could use the super-short:

    s.replace(/[a-zA-Z]/g,function(c){return String.fromCharCode((c<="Z"?90:122)>=(c=c.charCodeAt(0)+13)?c:c-26);});
    
  • While I really like the RegEx solution, I primarily undertook the project to see if I could get it done. Glad to report that I finally did manage to do so:

    String.prototype.rot13 = rot13 = function(s)
     {
        return (s ? s : this).split('').map(function(_)
         {
         if (!_.match(/[A-za-z]/)) return _;
         c = Math.floor(_.charCodeAt(0) / 97);
         k = (_.toLowerCase().charCodeAt(0) - 83) % 26 || 26;
         return String.fromCharCode(k + ((c == 0) ? 64 : 96));
         }).join('');
     }
    

0 comments:

Post a Comment