unlucky
unlucky

Reputation: 115

Caesar Cipher in Javascript

I am trying to write a program to solve the following problem in javascript (Written below this paragraph). I don't know why my code isn't working. Could someone help me? I'm new to javascript; this is a free code camp question.

"A common modern use is the ROT13 cipher, where the values of the letters are shifted by 13 places. Thus 'A' ↔ 'N', 'B' ↔ 'O' and so on.

Write a function which takes a ROT13 encoded string as input and returns a decoded string."

function rot13(str) { // LBH QVQ VG!
  
  var string = "";
  for(var i = 0; i < str.length; i++) {
    var temp = str.charAt(i);
    if(temp !== " " || temp!== "!" || temp!== "?") {
       string += String.fromCharCode(13 + String.prototype.charCodeAt(temp));
    } else {
      string += temp;
    }
  }
  
  return string;
}

// Change the inputs below to test
console.log(rot13("SERR PBQR PNZC")); //should decode to "FREE CODE CAMP"

Upvotes: 6

Views: 55570

Answers (20)

hol&#39;Up
hol&#39;Up

Reputation: 69

Here is my Solution when I finished the question.

function rot13(str) {
  if (typeof (str) !== "string") {
    throw new Error('Must be a String')
  }
  const alphabet = [
    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
    'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
    'U', 'V', 'W', 'X', 'Y', 'Z',
  ]

  str = str.split('') 

  for (let i = 0; i < str.length; i++) {
    const index = alphabet.findIndex((item) => item === str[i])
    if (index === -1) continue;
    if (index >= 13) str[i] = alphabet[index - 13];
    else if (index < 13) str[i] = alphabet[index + 13];
  }

  return str.join('')
}

here is my explanation about my code:

In this line, I split my code into an Array so I can do an iteration to my String.

str = str.split('')

Inside my iteration, I check the str value whether matches to the alphabet or not. And take the Alphabet index which value matches with the str element.

const index = alphabet.findIndex((item) => item === str[i])

if there's not matches from str element with the alphabet, then skip the iteration.

if (index === -1) continue;

the findIndex method will return -1 if not pass the test inside the callback.

if findIndex pass the test, it will return the index of the alphabet. and if its value >= 13, str[i] will got replaced with the alphabet[index - 13].

if (index >= 13) str[i] = alphabet[index - 13];

and if the index value is < 13, str[i] will be replaced with the alphabet[index + 13]

else if (index < 13) str[i] = alphabet[index + 13];

Upvotes: 1

Diego
Diego

Reputation: 356

My, my... My answer is just horribly differente from what I have read here... Here it goes:

function transformIntonumChar(letter) {
  let numChar;
  switch (letter) {
  case 'A':
    numChar = 0;
    break;
  case 'B':
    numChar = 1;
    break;
  case 'C':
    numChar = 2;
    break;
  case 'D':
    numChar = 3;
    break;
  case 'E':
    numChar = 4;
    break;
  case 'F':
    numChar = 5;
    break;
  case 'G':
    numChar = 6;
    break;
  case 'H':
    numChar = 7;
    break;
  case 'I':
    numChar = 8;
    break;
  case 'J':
    numChar = 9;
    break;
  case 'K':
    numChar = 10;
    break;
  case 'L':
    numChar = 11;
    break;
  case 'M':
    numChar = 12;
    break;
  case 'N':
    numChar = 13;
    break;
  case 'O':
    numChar = 14;
    break;
  case 'P':
    numChar = 15;
    break;
  case 'Q':
    numChar = 16;
    break;
  case 'R':
    numChar = 17;
    break;
  case 'S':
    numChar = 18;
    break;  
  case 'T':
    numChar = 19;
    break;
  case 'U':
    numChar = 20;
    break;
  case 'V':
    numChar = 21;
    break;
  case 'W':
    numChar = 22;
    break;
  case 'X':
    numChar = 23;
    break;
  case 'Y':
    numChar = 24;
    break;
  case 'Z':
    numChar = 25;
    break; 
    }
    return numChar;
}

function transformIntoLetter(numChar) {
  let letter;
  if (numChar < 0) {
      numChar = numChar + 26;
  }
  switch (numChar) {
  case 0:
    letter = "A";
    break;
  case 1:
    letter = "B";
    break;
  case 2:
    letter = "C";
    break;
  case 3:
    letter = "D";
    break;
  case 4:
    letter = "E";
    break;
  case 5:
    letter = "F";
    break;
  case 6:
    letter = "G";
    break;
  case 7:
    letter = "H";
    break;
  case 8:
    letter = "I";
    break;
  case 9:
    letter = "J";
    break;
  case 10:
    letter = "K";
    break;
  case 11:
    letter = "L";
    break;
  case 12:
    letter = "M";
    break;
  case 13:
    letter = "N";
    break;
  case 14:
    letter = "O";
    break;
  case 15:
    letter = "P";
    break;
  case 16:
    letter = "Q";
    break;
  case 17:
    letter = "R";
    break;
  case 18:
    letter = "S";
    break;  
  case 19:
    letter = "T";
    break;
  case 20:
    letter = "U";
    break;
  case 21:
    letter = "V";
    break;
  case 22:
    letter = "W";
    break;
  case 23:
    letter = "X";
    break;
  case 24:
    letter = "Y";
    break;
  case 25:
    letter = "Z";
    break; 
    }
    return letter;
}

function produceCodedStringArray(bigString) {
    let arrString = bigString.toUpperCase().split("");
    let codedArray = [];
    
    for (let i = 0; i < arrString.length; i++) {
        if ((/[A-Z]/).test(arrString[i])) {
            codedArray[i] = transformIntonumChar(arrString[i]);
            } else {
                codedArray[i] = arrString[i];
                }
    }
    return codedArray;
}

function deCodedString(codedArray) {
    let decodedArray = [];
    let decodedString;
    for (let i = 0; i < codedArray.length; i++) {
        if (typeof codedArray[i] === "number") {
            decodedArray[i] = transformIntoLetter(codedArray[i] - 13);
            } else {
                decodedArray[i] = codedArray[i];
                }
            decodedString = decodedArray.join("");
        }
    return decodedString;
}

function rot13(str) {
    let codedArray = produceCodedStringArray(str);
    let decodedString = deCodedString(codedArray);
  return decodedString;
}

It worked but... I am like "Meh!" Negative or positive feedback will be appreciated...

Upvotes: -1

Sefa_Kurtuldu
Sefa_Kurtuldu

Reputation: 24

Here is my approach to problem. First split is to get words.Second split is to get chars.Then checked is for uppercase Ascii and shifted the chars.End of all the Ascii numbers are converted to strings and they are joined.AsciUpper function is used to shift and get new ascii numbers.If ascii number is bigger than 90 (Z), the code starts with A again.

     function rot13(str) {
        const splittedStr = str.split(" ")
        for (let i in splittedStr) {
            splittedStr[i] = splittedStr[i]
            .split("")
            .map(item =>
                (65<=item.charCodeAt(0) && item.charCodeAt(0)<=90)
                ? asciUpper(item.charCodeAt(0)+13) 
                : item.charCodeAt(0)
                )
            }
        const strCode= splittedStr
        .map((items) => items
        .map((item) => String.fromCharCode(item)))
        const strJoinCode = strCode.map((items) => items.join(""))
        
        str = strJoinCode.join(" ");
        return str
    }
    function asciUpper(asciNum){
        if (asciNum>90){
        const more = asciNum % 90
        const cipNum = 64 + more
            return (cipNum)
        }else{
            return (asciNum)
        }
    }

    rot13("GUR DHVPX OEBJA SBK WHZCF BIRE GUR YNML QBT.")
    //THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG.
    rot13("SERR YBIR?")//FREE LOVE?

Upvotes: -1

Ala Eddine Menai
Ala Eddine Menai

Reputation: 2870

A simple solution with Built-in methods ( split, map, includes):

Code

function rot13(str) {
  const ALPHABETS = [...Array(26)].map((e, i) => (i + 10).toString(36).toUpperCase())
  const SHIFT = ALPHABETS.length / 2
  const SPECS = [" ", "!", "?", "."]

  return str.split("").map((char, i) => {
    if (SPECS.includes(char)) {
      return char
    } else {
      i = (ALPHABETS.indexOf(char) + SHIFT) % ALPHABETS.length
      return (ALPHABETS[i])
    }
  }).join("")
}


console.log(rot13("SERR PBQR PNZC"));
console.log(rot13("SERR CVMMN!"));
console.log(rot13("SERR YBIR?"));

Upvotes: -1

Adam Pietrasiak
Adam Pietrasiak

Reputation: 13204

Here is my approach - provide input and shift.

It maintains lower or upper case of original input and leave unprocessable letters in place:

ceasarCipher("Hello Stackoverflow!");
// Khoor Vwdfnryhuiorz!
function ceasarCipher(input: string, shift = 3) {
  const letters = input.split("");

  const anyLetter = /[a-z]/i;

  return letters
    .map((letter) => {
      if (!anyLetter.test(letter)) return letter;

      const upperLetter = letter.toUpperCase();

      const wasOriginalUpper = letter === upperLetter;

      const charCode = upperLetter.charCodeAt(0);

      //A = 65, Z = 90
      const maskedLetter = String.fromCharCode(
        charCode + shift <= 90
          ? charCode + shift
          : ((charCode + shift) % 90) + 64
      );

      if (wasOriginalUpper) {
        return maskedLetter;
      }

      return maskedLetter.toLowerCase();
    })
    .join("");
}

Upvotes: -1

Reza Sohrabi
Reza Sohrabi

Reputation: 37

Solution using for loop, in each iteration check if character is alphabet then decode it by subtracting 13 from it's ascii code, if decoded character is not alphabet (its ascii code is less than 65), then decode it by adding 13 to it.

function rot13(str) {

  function isAlphabet(char) {
    return String(char).match(/[A-Z]/);
  }

  const chars = str.split("");

  for(let i = 0 ; i < chars.length; i++) {
    const char = chars[i];
    if(isAlphabet(char)) {
      const decoded = String.fromCharCode(char.charCodeAt() - 13);
      const decodedAlphabet = String.fromCharCode(char.charCodeAt() + 13);
      chars[i] = isAlphabet(decoded)? decoded : decodedAlphabet;
    }
  }

  return chars.join("")
}

Upvotes: -1

I wanted to post my way to do it in typestcript.

    function caesarCipher(s: string, k: number): string {
        //[ [ 'A', 65 ], [ 'Z', 90 ], [ 'a', 97 ], [ 'z', 122 ] ]

        return [...s]
            .map(l => (l.charCodeAt(0)))
            .map(n => n >= 65 && n <= 90 ? ((n - 65 + k) % 26) + 65 : n)
            .map(n => n >= 97 && n <= 122 ? ((n - 97 + k) % 26) + 97 : n)
            .map(n => String.fromCharCode(n))
            .join("")
    }

Upvotes: -1

Ali Tauseef Reza
Ali Tauseef Reza

Reputation: 53

This problem can be solved in many ways. Below is the code using ASCII code of the characters in ths string and with two built in JavaScript functions i.e., charCodeAt() and String.fromCharCode()

function rot13(message) {
let cipherString = '';
let arr = [...message];
for (let i = 0; i < arr.length; i++) {
    let asciiValue = arr[i].charCodeAt();
    if (
        (asciiValue >= 65 && asciiValue <= 90) ||
        (asciiValue >= 97 && asciiValue <= 122)
    ) {
        if (asciiValue >= 65 && asciiValue <= 90) {
            if (asciiValue <= 77) {
                asciiValue += 13;
            } else {
                asciiValue -= 13;
            }
        } else {
            if (asciiValue <= 109) {
                asciiValue += 13;
            } else {
                asciiValue -= 13;
            }
        }
        cipherString += String.fromCharCode(asciiValue);
    } else cipherString += arr[i];
}
return cipherString;

}

Upvotes: -1

Anurag
Anurag

Reputation: 83

Here's a simple solution.

function caesar(str) {

    str = str.split("")
    str = str.map(char => {
                            
        let code = char.charCodeAt(0)

        if( (code > 64 && code < 78) || (code > 96 && code < 110) )
            code += 13

        else if ( (code > 77 && code < 91) || (code > 109 && code < 123) )
            code -= 13
        
        return String.fromCharCode(code)
    })

    return str.join("")
}

Upvotes: 0

Ali Mustafa
Ali Mustafa

Reputation: 764

I see that people here have written lengthy codes. I have solved the problem using a simple solution.

function replacing(str){
let strAm = "ABCDEFGHIJKLMNOPQRSTUVWXYZ -_.&?!@ #/";
let strNz = "NOPQRSTUVWXYZABCDEFGHIJKLM -_.&?!@ #/";
  let rot13 = '';
  for (let i = 0; i < str.length; i++){
    if (strAm.includes(str.charAt(i))){
      rot13 += str.charAt(i).replace(str.charAt(i), strNz[strAm.indexOf(str.charAt(i))]);
    }
  }
  return rot13;
}
console.log(replacing("GUR DHVPX OEBJA SBK WHZCF BIRE GUR YNML QBT."));

Upvotes: 0

hermawan
hermawan

Reputation: 9

I just solved the caesar chipper problem using this algorithm.

function rot13(str) {
const rot13 = {
  'N': "A",
  'O': 'B',
  'P': 'C',
  'Q': 'D',
  'R': 'E',
  'S': 'F',
  'T': 'G',
  'U': 'H',
  'V': 'I',
  'W': 'J',
  'X': 'K',
  'Y': 'L',
  'Z': 'M',
  'A': 'N',
  'B': 'O',
  'C': 'P',
  'D': 'Q',
  'E': 'R',
  'F': 'S',
  'G': 'T',
  'H': 'U',
  'I': 'V',
  'J': 'W',
  'K': 'X',
  'L': 'Y',
  'M': 'Z'
}
const splitStr = str.split(' ').map(string => {
  return string.split('').map(string => rot13[string] === undefined ? string : rot13[string]).join('');
}).join(' ');
  return splitStr;
}

Upvotes: 0

Muhammad Abdullah
Muhammad Abdullah

Reputation: 4515

Note : This function will take care of alphabetic(a-z or A-Z) and all others will be ignored.

Considered points are

  1. Handle negative number

  2. Can take care of big number.

  3. Handle special character, number and space will print as it is sd

    function caesarCipher(word, next) { next = next % 26; let res = ""; for (const letter of word) {

    let letterCode = letter.charCodeAt(0);
    if (letterCode >= 65 && letterCode <= 90) {
      letterCode = letterCode + next;
      if (letterCode > 90) {
        letterCode = letterCode - 26;
      } else if (letterCode < 65) {
        letterCode = letterCode + 26;
      }
    } else if (letterCode >= 97 && letterCode <= 122) {
      letterCode = letterCode + next;
    
      if (letterCode > 122) {
        letterCode = letterCode - 26;
      } else if (letterCode < 97) {
        letterCode = letterCode + 26;
      }
    }
    
        res = res + String.fromCharCode(letterCode);
      }
    
    return res;  }
    
    console.log(caesarCipher("Zoo  Keeper 666  %^&*(", 2));
    console.log(caesarCipher("Big Car", -16));
    

Output

Bqq  Mggrgt 666  %^&*(
Lsq Mkb

Upvotes: 1

Chetan Nada
Chetan Nada

Reputation: 86

I have tried to make it simple and I earned FREE PIZZA!. Check my solution for this.

    function rot13(str) {
    
    var alphabets =['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'," ", "-", "_", ".", "&","?", "!", "@", "#", "/"];
    
    var alphabets13 = ['N','O','P','Q','R','S','T','U','V','W','X','Y','Z','A','B','C','D','E','F','G','H','I','J','K','L','M', " ", "-", "_", ".", "&","?", "!", "@", "#", "/"];
    
    var resultStr = [];
    for(let i=0; i<str.length; i++){
        for(let j =0; j<alphabets.length; j++){
            if(str[i] === alphabets[j]){
            resultStr.push(alphabets13[j]);
            }
        }
    }
    return resultStr.join("");
  };

  rot13("SERR CVMMN!");

Upvotes: 5

PureKaoZ
PureKaoZ

Reputation: 11

I just recently solved a caesar cipher algorithm problem that works similarly to your rot13, but will take any integer value as a shift parameter. One of the issues I notice with your code is you are already assigning temp as a number by assigning the charCode for the character at 'i'. This makes your conditional obsolete, since it will never identify the string values, since you're passing in a number value. Also, when you build the string, it should just be 'String.fromCharCode(13 + temp)'. I personally prefer the caesar cipher, since you can assign random shift parameters.

Here's an example of how I wrote it:

// s = string to encrypt, k = shift value
// s = 'SERR PBQR PNZC' and k = 13 will produce 'FREE CODE CAMP'
const caesarCipher = function(s, k) {
  let result = '';
  
  for (let i = 0; i < s.length; i++) {

    let charCode = s[i].charCodeAt();
    // check that charCode is a lowercase letter; automatically ignores non-letters
    if (charCode > 96 && charCode < 123) {
      
      charCode += k % 26 // makes it work with numbers greater than 26 to maintain correct shift
      // if shift passes 'z', resets to 'a' to maintain looping shift
      if (charCode > 122) {
        charCode = (charCode - 122) + 96;
      // same as previous, but checking shift doesn't pass 'a' when shifting negative numbers
      } else if (charCode < 97) {
        charCode = (charCode - 97) + 123;
      }
    }

    if (charCode > 64 && charCode < 91) {
      
      charCode += k % 26
      
      if (charCode > 90) {
        charCode = (charCode - 90) + 64;
      } else if (charCode < 65) {
        charCode = (charCode - 65) + 91;
      }
    }

    result += String.fromCharCode(charCode);
  }
  return result
}

Upvotes: 1

Amin Matola
Amin Matola

Reputation: 177

I am recently in my first stage of developing a javascript library to simplify my daily programming requirements. One of which is Encryption.

The library uses caesar encryption as of now.

You may download the minified version in the early development and use it in your html pages as:

d(window).loaded(function() {

  /* *
   * Tidy up the heading
   * */
  d("h1")
    .background("#fafafa")
    .color("orange");

  /* *
   * Encrypt all paragraphs and maximize the height so we view each paragraph separately
   * */
  d("p")
    .encrypt(text = "", depth = 15)
    .resize("60%", "50px");

  /* *
   * Show up the first paragraph element's html
   * */
  _.popUp("First Paragraph: <hr>" + dom("p").getText(), "", "purple")
})

/* *
 * Show the inputed text in below snippet
 * */
function showEncryptedText(){
    d("#encrypted")
    .encrypt(d("#plain").c[0].value, 15)
    .background("#e8e8e8")
    .resize("100%", "100px");

}
<!DOCTYPE HTML>
<html>

<head>
  <title>Element Encryption</title>
  <script type="text/javascript" src="https://raw.githubusercontent.com/Amin-Matola/domjs/master/dom-v1.0.0/dom.min.js"></script>
</head>

<body>
  <h1>Javascript Encryption</h1>

  <p>This is the first paragraph you may encrypt</p>
  <p>This is another paragraph you may encrypt</p>
  <p>You may encrypt this too</p>
  <h2>You may even provide your text to be encrypted</h2>
  <div id="encrypted">
  
  </div>
  
  <input type="text" id="plain" value="" name="mydata" oninput="showEncryptedText()"/>
  </div>

  <footer>
    <!--- you may place your js here --->
    <script type="text/javascript">
    </script>
</body>

</html>

Upvotes: 0

Mourad Sidhoumi
Mourad Sidhoumi

Reputation: 111

Using modulus operator; makes the sentence uppercase;

function cipherRot13(str) {
  str = str.toUpperCase();
  return str.replace(/[A-Z]/g, rot13);

  function rot13(correspondance) {
    const charCode = correspondance.charCodeAt();
    //A = 65, Z = 90
    return String.fromCharCode(
            ((charCode + 13) <= 90) ? charCode + 13
                                    : (charCode + 13) % 90 + 64
           );
    
  }
}

Upvotes: 11

jefelewis
jefelewis

Reputation: 2059

2020 TypeScript Version:

  • A shift argument must be given, but you can choose 13 for rot13 or any other number.
// TypeScript Type: Alphabet
type Alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';

// Helper Function: Caesar Cipher
export const caesarCipher = (string: string, shift: number) => {
  // Alphabet
  const alphabet: Alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';

  // Encoded Text
  let encodedText: string = '';

  // Adjust Shift (Over 26 Characters)
  if (shift > 26) {
    // Assign Remainder As Shift
    shift = shift % 26;
  }

  // Iterate Over Data
  let i: number = 0;
  while (i < string.length) {
    // Valid Alphabet Characters
    if (alphabet.indexOf(string[i]) !== -1) {
      // Find Alphabet Index
      const alphabetIndex: number = alphabet.indexOf((string[i]).toUpperCase());

      // Alphabet Index Is In Alphabet Range
      if (alphabet[alphabetIndex + shift]) {
        // Append To String
        encodedText += alphabet[alphabetIndex + shift];
      }
      // Alphabet Index Out Of Range (Adjust Alphabet By 26 Characters)
      else {
        // Append To String
        encodedText += alphabet[alphabetIndex + shift - 26];
      }
    }
    // Special Characters
    else {
      // Append To String
      encodedText += string[i];
    }

    // Increase I
    i++;
  }

  return encodedText;
};

Example #1:

console.log(caesarCipher('ABCDEFGHIJKLMNOPQRSTUVWXYZ', 2));

Output:
CDEFGHIJKLMNOPQRSTUVWXYZAB

Example #2:

console.log(caesarCipher('GUR DHVPX OEBJA QBT WHZCRQ BIRE GUR YNML SBK.', 26 + 13));

Output:
THE QUICK BROWN DOG JUMPED OVER THE LAZY FOX.

Upvotes: 0

Bragaru Ion
Bragaru Ion

Reputation: 1

const rot13 = (string) => {
//  creating *letterBox* - string in alphabetic way
  const letterBox = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
// declaring *iter function* - that will pass through the text 
  const iter = (str, acc) => {   
// if length of string is 0 (phrase is empty) => returning *accumulator*
      if (str.length===0) { return acc; }
/* if is not an uppercase character => calling *function iter* by itself 
with the new string minus first letter and adding to *accumulator*
without coding symbol */ 
      if (! /^[A-Z]*$/.test(str[0])) {return iter(str.substring(1), acc+str[0]); };
// and now we loop through the uppercase letters (26 letters)
//checking their index in our *letterBox*
// if it's more that 13 , we add 13 , else we substract 13 and   
// and of course... calling *iter function* with new string minus first character 
// plus *accumumator* 
     for (let i=0; i<26;i++)
     {
       if ( (letterBox[i]===str[0]) && (i>12))
       { return iter(str.substring(1), acc + letterBox[i-13]); }
       if ( (letterBox[i]===str[0])&& (i<13))
       { return  iter(str.substring(1), acc + letterBox[i+13]); };
      };
  };
 // calling *iter function* with the provided *string* and empty *accumulator*    
 return iter(string,'');
};
   console.log(rot13('GUR DHVPX OEBJA SBK WHZCF BIRE GUR YNML QBT.'));
// THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG.

passed with success test on codecamp. also there is another version.. without iter function



const rot13=(str) =>
{
    var alph= "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    let result ='';
    while(str.length>0)
  {

  for (let i=0;i<=25;i++)
     { 
       if ((alph[i]===str[0]) && (i>13)) {result = result + alph[i-13];};
       if ((alph[i]===str[0]) && (i<13)) {result = result + alph[i+13] ;} ;
      };
 if (!  /^[A-Z]*$/.test(str[0]) ) {result = result+ str[0];}; 
str=str.substring(1);
   };   
  return result;          
};

console.log(rot13('SERR YBIR?'));
// returns FREE LOVE?

Upvotes: 0

codeguppy
codeguppy

Reputation: 175

You can build the algorithm for ROT13 directly... or just use a Caesar Cipher algorithm with the appropriate key.

The alternative that I'm proposing to your example is just a particular usage of a regular Caesar Cipher algorithm – a very simple form of encryption, in which each letter in the original message is shifted to the left or right by a certain number of positions.

To decrypt the message we simply shift back the letters the same number of positions.

Example:

  • JAVASCRIPT becomes MDYDVFULSW if we shift all letters by 3 positions
  • MDYDVFULSW turns back to JAVASCRIPT if we shift back all letters by 3 positions.

If after shifting a letter goes outside the range of letters, then the letter is wrapped around in alphabet. Example: Letter Z becomes C if is shifted by 3 positions.

This “wrap-around” effect means use of modulo. In mathematical terms, the above can be expressed as this:

En(x) = (x + n) mod 26

Dn(x) = (x – n) mod 26

Trying to implement this algorithm in JavaScript without the use of a proper modulo operator will produce either incorrect results or a very cryptic and difficult to understand code.

The biggest problem is that JavaScript doesn't contain a modulo operator. The % operator is just the reminder of the division - not modulo. However, it is pretty easy to implement modulo as a custom function:

// Implement modulo by replacing the negative operand 
// with an equivalent positive operand that has the same wrap-around effect
function mod(n, p)
{
    if ( n < 0 )
        n = p - Math.abs(n) % p;

    return n % p;
}

There are other ways of implementing modulo... if you are interested you can consult this article.

By using the mod function defined above, the code expresses the mathematical equation identically:

// Function will implement Caesar Cipher to
// encrypt / decrypt the msg by shifting the letters
// of the message acording to the key
function encrypt(msg, key)
{
    var encMsg = "";

    for(var i = 0; i < msg.length; i++)
    {
        var code = msg.charCodeAt(i);

        // Encrypt only letters in 'A' ... 'Z' interval
        if (code >= 65 && code <= 65 + 26 - 1)
        {
            code -= 65;
            code = mod(code + key, 26);
            code += 65;
        }

        encMsg += String.fromCharCode(code);
    }

    return encMsg;
}

To encode using ROT13 ... is now just a matter of choosing the appropriate key as indicated by algorithm name.

Upvotes: 1

Glen Pierce
Glen Pierce

Reputation: 4831

While A + 13 may equal N, Z + 13 will not compute correctly.

Upvotes: -1

Related Questions