5
\$\begingroup\$

Very new to coding, so please don't bully me.

Implement the legendary caesar cipher:

In cryptography, a Caesar cipher, also known as Caesar's cipher, the shift cipher, Caesar's code or Caesar shift, is one of the simplest and most widely known encryption techniques. It is a type of substitution cipher in which each letter in the plaintext is replaced by a letter some fixed number of positions down the alphabet. For example, with a left shift of 3, D would be replaced by A, E would become B, and so on. The method is named after Julius Caesar, who used it in his private correspondence.

Question: Write a function that takes a string to be encoded and a shift factor and then returns the encoded string:

caesar('A', 1) // simply shifts the letter by 1: returns 'B' the cipher should retain capitalization:

caesar('Hey', 5) // returns 'Mjd; should not shift punctuation:

caesar('Hello, World!', 5) //returns 'Mjqqt, Btwqi!' the shift should wrap around the alphabet:

caesar('Z', 1) // returns 'A' negative numbers should work as well:

caesar('Mjqqt, Btwqi!', -5) // returns 'Hello, World!'

My Solution:

function caesar(string, num) {
let arr = [];
for(let i=0;i<string.length;i++)
  {if(!(/[a-zA-Z]/.test(string[i])))
    {arr[i]=string[i]; continue;}
  let n = string.charCodeAt(i) + num;
  if (string[i] == string[i].toLowerCase()) 
    {if(n>122)  
      {while(n>122)
        {n-=26;}} 
     else  
      {while(n<97)
        {n+=26;}
      }
    }
  else
    {if(n>90)
      {while(n>90)
        {n-=26;}
      } 
     else 
      {while(n<65)
        {n+=26;}
      }
    }
  arr[i]=String.fromCharCode(n);    
  }
console.log(arr.join(''));
}
caesar("Hello, World!", 2);
caesar("Hello, World!", 75);

The code is working perfectly as per requirement, but please help me with a better solution if possible.

And if you do, please use comments to extensively explain the working process, as I'm quite the noob.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Welcome to code review. We can't provide alternate code solutions, we do review the code and make comments. \$\endgroup\$
    – pacmaninbw
    Commented May 29, 2020 at 0:22
  • \$\begingroup\$ @pacmaninbw Okay, then. Thank you for your time. :) \$\endgroup\$
    – Adil Ahmed
    Commented May 29, 2020 at 2:36

1 Answer 1

4
\$\begingroup\$

Welcome to Code Review, some considerations that can help you to simplify your code:

  1. you have an alphabet of 26 letters, so if the shifting operation is limited to a 26 characters range you can use the mod operation %26 to determine the final position.
  2. you can have a shift negative operation num (ex. -5), for a 26 set of elements shift this is equal to a positive shift of Math.abs(26 - Math.abs(num)) , so for 5 the positive shift is 21.

So if you have a c character and you want to obtain the ascii code of the corresponding shifted char of num positions you can obtain it in the following way:

const start = c === c.toLowerCase() ? 'a'.charCodeAt(0) : 'A'.charCodeAt(0);
const diff = c.charCodeAt(0) - start;
const sh = num >= 0 ? diff + num : diff + Math.abs(26 - Math.abs(num));
const code = sh % 26 + start;

The first line returns the ascii code of 'a' or 'A' depending if the char c is lowercase or uppercase called start, the second gives you the difference between c and start, the last two lines calculate the code of the shifted corresponding character.

After your function can be rewritten in the following way:

'use strict';

function caesar(str, num) {
    const arr = [];
    const re = /[a-zA-Z]/;
    for (const c of str) {
        if (re.test(c)) {
            const start = c === c.toLowerCase() ? 'a'.charCodeAt(0) : 'A'.charCodeAt(0);
            const diff = c.charCodeAt(0) - start;
            const sh = num >= 0 ? diff + num : diff + Math.abs(26 - Math.abs(num));
            const code = sh % 26 + start;
            arr.push(String.fromCharCode(code));
        } else { 
            arr.push(c); 
        }
    }

    return arr.join('');
}

I set arr and regex as const and instead of iterate over string using the index, I preferred the for ... of construct.

Note: I'm a javascript beginner too, so every suggestion to improve my code as for the original question is highly appreciated.

\$\endgroup\$
7
  • \$\begingroup\$ Yes yes, stupid me totally forgot about absolute value function. And yes, using ternary operator does help a lot in solidifying the code and making it more readable. Thank you for the help. Certainly appreciate it. \$\endgroup\$
    – Adil Ahmed
    Commented May 29, 2020 at 12:41
  • 1
    \$\begingroup\$ @AdilAhmed You are welcome. \$\endgroup\$ Commented May 29, 2020 at 15:42
  • 1
    \$\begingroup\$ Given you stated: “every suggestion to improve my code as for the original question is highly appreciated.” Feel free to create a new question, linking to this post, and use the tag rags-to-riches \$\endgroup\$ Commented Feb 25, 2021 at 7:44
  • \$\begingroup\$ @SᴀᴍOnᴇᴌᴀ Thank you for your suggestion and for the link, I was not aware about the rags-to-riches tag. \$\endgroup\$ Commented Feb 25, 2021 at 8:05
  • 1
    \$\begingroup\$ I took your code to compare to mine in Odin project. Your code failed the large negative test included in that part of the project. The change I proposed solved it on my side. But I went quickly on it to be hones :) \$\endgroup\$ Commented Oct 23, 2022 at 8:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.