0

I have written a function where the values of the letters in a received string are shifted by 13 places.

My solution is highly inefficient and would need completely rewriting if the shift factor was changed.

Here is my solution:

function rot13(str) {
  var charArray = str.split("");
  var myArray = [];

  for (var i = 0; i < charArray.length; i++) {
    switch (charArray[i]) {

      case "A":
        myArray.push("N");
        break;

      case "B":
        myArray.push("O");
        break;

      case "C":
        myArray.push("P");
        break;

      case "D":
        myArray.push("Q");
        break;

      case "E":
        myArray.push("R");
        break;

      case "F":
        myArray.push("S");
        break;

      case "G":
        myArray.push("T");
        break;

      case "H":
        myArray.push("U");
        break;

      case "I":
        myArray.push("V");
        break;

      case "J":
        myArray.push("W");
        break;

      case "K":
        myArray.push("X");
        break;

      case "L":
        myArray.push("Y");
        break;

      case "M":
        myArray.push("Z");
        break;

      case "N":
        myArray.push("A");
        break;

      case "O":
        myArray.push("B");
        break;

      case "P":
        myArray.push("C");
        break;

      case "Q":
        myArray.push("D");
        break;

      case "R":
        myArray.push("E");
        break;

      case "S":
        myArray.push("F");
        break;

      case "T":
        myArray.push("G");
        break;

      case "U":
        myArray.push("H");
        break;

      case "V":
        myArray.push("I");
        break;

      case "W":
        myArray.push("J");
        break;

      case "X":
        myArray.push("K");
        break;

      case "Y":
        myArray.push("L");
        break;

      case "Z":
        myArray.push("M");
        break;

      case " ":
        myArray.push(" ");
        break;

      case ",":
        myArray.push(",");
        break;

      case "!":
        myArray.push("!");
        break;

      case "?":
        myArray.push("?");
        break;

      case ".":
        myArray.push(".");
        break;
    }
  }

 

  console.log(myArray.join(""));

}
rot13("GUR DHVPX OEBJA QBT WHZCRQ BIRE GUR YNML SBK.");

Can you show me a more efficient less cumbersome solution?

Kōdo no musō-ka
  • 769
  • 1
  • 8
  • 23
  • 3
    Tip: `var map = {A: 'N', ...}` Tip 2: `String.fromCharCode(str.charCodeAt(...) + 13)`… – deceze Nov 22 '16 at 15:56
  • 3
    This question could be suitable for [Code Review](http://codereview.stackexchange.com/help), as long as (a) your code works as intended, (b) your code is real code, rather than example code, and (c) your code is included in the body of the question. If you wish for a peer review to improve all aspects of your code, please post it on Code Review. – Heretic Monkey Nov 22 '16 at 15:58
  • Maybe using their ASCII values and then shifting them by an arbitrary number, in this case 13? – mzdv Nov 22 '16 at 16:05
  • Possible duplicate of [Where is my one-line implementation of rot13 in JavaScript going wrong?](http://stackoverflow.com/q/617647/1529630) – Oriol Nov 22 '16 at 16:15

4 Answers4

2

Here's one possible implementation, with the ability to pass in any (positive) rotation value and a table of other replacements. Written in ES6.

function rotn(str, rotation = 13, map = {}) {
    const table = {};  // New table, to avoid mutating the parameter passed in
    // Establish mappings for the characters passed in initially
    for (var key in map) {
        table[map[key]] = key;
        table[key] = map[key];
    }
    // Then build the rotation map.
    // 65 and 97 are the character codes for A and a, respectively.
    for (var i = 0; i < 26; i++) {
        table[String.fromCharCode(65 + i)] = String.fromCharCode(65 + (i + rotation) % 26);
        table[String.fromCharCode(97 + i)] = String.fromCharCode(97 + (i + rotation) % 26);
    }

    return str.split('').map((c) => table[c] || c).join('');
}


console.log(rotn("Gur dhvpx oebja Qbt whzcrq bire gur ynml Sbk.", 13, {'.': '!'}));
AKX
  • 152,115
  • 15
  • 115
  • 172
1

Here is an example using the reduce function:

function rot13(str) {
  chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  return str.split("").reduce(function(a, b) {
    if (chars.indexOf(b) == -1) {
      return a + b;
    }
    return a + chars[(chars.indexOf(b)+13) % chars.length]
  }, "");
}

console.log(rot13("GUR DHVPX OEBJA QBT WHZCRQ BIRE GUR YNML SBK."));
Dekel
  • 60,707
  • 10
  • 101
  • 129
  • Why don't you check whether `b` is in `chars` instead of `extra_chars`? Then you don't need to specify what's an extra character. – L3viathan Nov 22 '16 at 16:11
0
function ROT13 (str){
    var result = "";
    for (var i = 0; i < str.length; i++) {
        var charCode = str.charCodeAt(i);
        if (charCode >= 65 && charCode <= 90) {
        result += String.fromCharCode(((charCode - 65 + 13) % 26) + 65);
        } else if (charCode >= 97 && charCode <= 122) {
        result += String.fromCharCode(((charCode - 97 + 13) % 26) + 97);
        } else {
        result += str[i];
        }
    }
    return result;
}
0

Here's a solution that uses:

  • replace() with a /[a-z]/ regex so that only alphabetic characters will be modified
  • indexOf() to convert that alphabetic character to an index
  • then uses that index to lookup the corresponding cipher character

function rot13(txt) {
    return txt.replace(/[a-z]/gi, c =>
        "NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm"
      [ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".indexOf(c) ] );
}

console.log(rot13("GUR DHVPX OEBJA QBT WHZCRQ BIRE GUR YNML SBK."));
Stephen Quan
  • 21,481
  • 4
  • 88
  • 75