DEV Community

Cover image for Writing A Caesar Shift Cipher Function with JavaScript: Part 1
Lucia Cerchie
Lucia Cerchie

Posted on • Edited on

Writing A Caesar Shift Cipher Function with JavaScript: Part 1

A Caesar cipher is an encryption technique. You take each letter in a word, and shift it forward by a certain number of alphabetical degrees to obscure its meaning. Thus, 'cab' with a degree shift of 1 become 'dbc'. The person you send the cipher to knows the number and shift degree to decode it back to its original meaning.

I wanted to write a function that would take in two parameters, shiftDegrees and inputText, and return a string that shifted each letter forward by the specified degree.

So I started out with:

function caesarShift(inputText, shiftDegrees) { 

}
Enter fullscreen mode Exit fullscreen mode

I also needed an alphabet to refer this function to, so I pulled in an array:

const lowerCaseAlphabet = [
    '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',
]
Enter fullscreen mode Exit fullscreen mode

Now to attend to the edge-cases! If I'm honest, these occurred to me towards the end of writing the function, but I put them at the top of my logic so I'm explaining them now. Inside the function I have:

    if (shiftDegrees > 26 || shiftDegrees < -26) {
        return 'use a shift between -26 and 26'
    }
Enter fullscreen mode Exit fullscreen mode

Another solution would be take 26 as a factor of any numbers greater than it and then take the remainder as the shiftDegree. It's a stretch goal for me, but you're welcome to add your solution in the comments.

The other edge cases were invalid params:

    if (typeof shiftDegrees != 'number') {
        return 'shiftDegree must be a number'
    }
    if (typeof inputText != 'string') {
        return 'inputText must be string'
    }
Enter fullscreen mode Exit fullscreen mode

Then it was time to eliminate capitalization issues:

const inputTextToLowerCase = inputText.toLowerCase()
Enter fullscreen mode Exit fullscreen mode

I'm also going to want to capture the indexes of each letter in the inputString, so I set this variable to an empty array:

let arrayOfAlphaIdxes = []
Enter fullscreen mode Exit fullscreen mode

Now, to isolate the indexes of each letter in my input word, I ran a couple for loops:

    for (let i = 0; i < inputText.length; i++) {
        for (let j = 0; j < lowerCaseAlphabet.length; j++) {
            if (inputTextToLowerCase[i] === lowerCaseAlphabet[j]) {
                arrayOfAlphaIdxes.push(j)
            }
        }
    }
Enter fullscreen mode Exit fullscreen mode

Basically what this does is run through the length of the inputText string, and match each value of each letter to an index in the alphabet. Then I pushed that new value to an array, arrayOfAlphaIdxes.

Now, I needed to move those indexes. I did another for loop and added shiftDegrees to each one and pushed it to arrayOfMovedAlphaIdxes, so arrayOfMovedAlphaIdxes represented the Caesar-shifted indexes.

The last thing to do is take the values of the letters at each of the new indexes and translate them into a new string:

 // for loop that creates an array of new letters with the new shifted indexes
    arrayWithNewLetters = []
    for (let i = 0; i < arrayOfMovedAlphaIdxes.length; i++) {
        for (let j = 0; j < lowerCaseAlphabet.length; j++) {
            if (arrayOfMovedAlphaIdxes[i] === j) {
                arrayWithNewLetters.push(lowerCaseAlphabet[j])
            }
        }
    }
Enter fullscreen mode Exit fullscreen mode

I did this by creating an empty array, and pushing the new values to it with a double for loop to capture the values from the array of indexes and from the alphabet.

The last piece of the puzzle was to create a string to return:

    const stringWithCommas = arrayWithNewLetters.toString()

    const removedCommas = stringWithCommas.split(',').join('')

    return removedCommas
Enter fullscreen mode Exit fullscreen mode

At this point, this function:

caesarShift('HELLO', 2)
Enter fullscreen mode Exit fullscreen mode

had this output:

jgnnq
Enter fullscreen mode Exit fullscreen mode

This looks like the function is outputting what we want, but let's try a higher shift degree:

caesarShift('HELLO', 20)
Enter fullscreen mode Exit fullscreen mode

outputs:

y
Enter fullscreen mode Exit fullscreen mode

The response is truncated! I forgot to add logic to make the index count 'wrap around', so to speak, the alphabet array. What to do now? Well, let's get to know our unknowns. The first unknown is the distance from the end. Because the distance of the array is fixed, I found that by doing this:

 let distanceFromEndIncludingCurrentLetter = 27 - arrayOfAlphaIdxes[i]
Enter fullscreen mode Exit fullscreen mode

Now we know that if shiftDegrees is greater than the distance from the end, then we'll need to do some triage.

How to fix the issue? Well, we do know that the difference between shiftDegrees and the distance to the end is the number of indexes we'll need to shift the value from the beginning in order to 'loop' the array. So we'll assign the new index by that delta, shiftDegrees - distanceFromEndIncludingCurrentLetter.

In the end I changed my function to:

    //for loop that changes the arrayindex by shift number
    for (let i = 0; i < arrayOfAlphaIdxes.length; i++) {
        let distanceFromEndIncludingCurrentLetter = 27 - arrayOfAlphaIdxes[i]
        if (shiftDegrees < distanceFromEndIncludingCurrentLetter) {
            let newIdx = arrayOfAlphaIdxes[i] + shiftDegrees
            arrayOfMovedAlphaIdxes.push(newIdx)
        } else {
            let differenceBtw =
                shiftDegrees - distanceFromEndIncludingCurrentLetter
            arrayOfMovedAlphaIdxes.push(differenceBtw)
        }
    }
Enter fullscreen mode Exit fullscreen mode

The full code is on my Github profile if you're interested! I'd love to hear feedback. ❤️

Top comments (0)