Caesars Cipher Rot13 - problem with String.fromCharCode();


#1

Hello fellow coders. I’m getting frustrated with this one. I’m pretty the logic in my code is consistant, but it isn’t! All I get when I execute the code is the non-computable red dot in console. I have locked in the hint-section, but I wanna make my own approach work. What am I doing wrong?

function rot13(str) { // LBH QVQ VG!
  
  var newArray = [];
  
  
  for (var i = 0; i < str.length; i++){
    if (str[i] !== " ", ".",",","!","?"){
      newArray.push(str[i].charCodeAt()-13);
    } else {
      newArray.push(str[i].charCodeAt());
    }
 }
  
   var newArrayToString = newArray.toString();
   var charCodeToString = String.fromCharCode(newArrayToString);  

  return charCodeToString;
  
  
}

// Change the inputs below to test
rot13("SERR PBQR PNZC");

#2

what line is the red dot showing on ?


#3

there is no combo comparison expression in javascript - you can compare two values at a time with === or !== - you can combine two comparisons with && or ||

this is invalid syntax

if (str[i] !== " ", ".",",","!","?"){


#4

You have several problems in your code. I will help you out with one that if fixed, will give you something to work with.
Your line:

var newArrayToString = newArray.toString();

After this line executes newArrayToString is a string that looks like:

70,56,69,69,19,67,53,68,69,19,67,65,77,54

String.fromCharCode() takes a sequence of numbers that are Unicode values. You instead have provided it a single string value (newArrayToString). You could supply the array you already created (newArray) and apply it to the function as follows:

var convertedArray = String.fromCharCode(null,newArray);

and then convert the array back to a string, but you are still going to have to do some work on the code in your for loop as pointed out by @ppc to get to a finale solution. As it stands, newArray does not have the correct values in it which String.fromCharCode will create the correct answer.


#5

Thanks. I did fix that just after posting :slight_smile:


#6

Thanks a lot for your reply. That helped me a lot. I did rework the loop and now it works. I just had to grasp the charcode concept and the charcode methods inside my loop.

The only thing I’m left without understanding is why .apply and null is used to make the fromCharCode method work?

Here is the final code (not pretty, but it works):

function rot13(str) { 
  
 // newArray to receive converted values
  
  var newArray = [];
  
 // for-loop to iterate through string and push the converted values to newArray 
  
  for (var i = 0; i < str.length; i++){
    if ((str[i].charCodeAt() < 65) || (str[i].charCodeAt() > 90)){
      newArray.push(str[i].charCodeAt());
    } else if (str[i].charCodeAt() < 78) {
      newArray.push(str[i].charCodeAt()+13);
    } else {
      newArray.push(str[i].charCodeAt()-13);
    }
 }
  
 // Variable to return that uses String.fromCharCode() method to covert charcodes in newArray back to string.  
  
   var charCodeToString = String.fromCharCode.apply(null, newArray);  

  return charCodeToString; 
}

// Change the inputs below to test
rot13("LBH QVQ VG!");

Returns “YOU DID IT!” in console :slight_smile:


#7

My answer is long-winded for good reasons

First - it’s better to use the newer fromCodePoint function instead of fromCharCode - it handles non-English languages better than the older API - it does not affect this problem since rot13 only makes sense for English

Second - about apply - there’s a new better way to avoid it that I explain below

You’ll notice the docs for fromCodePoint (and fromCharCode) say

Syntax

String.fromCodePoint(num1[, ...[, numN]])

Parameters

num1, ..., numN
A sequence of code points

The brackets in the syntax (num1[, ...[, numN]]) do not mean an array - rather [] here means optional parameters - it means the function can take 1 or 2 or 3 or any number of numeric values as parameters

There are other functions like this - e.g. string concat also takes a variable number of arguments

This is fine if you have separate values like

String.fromCodePoint(65, 66, 67)
// "ABC"

this does not work for an array for obvious reasons - the function takes numbers not arrays

String.fromCodePoint([65, 66, 67])
// Invalid code point NaN error

So how do we use the function if there’s a bunch of values that are not separated out but in an array

latest javascript provides the triple-dot spread operator ... for repurposing an array as a separated list of values - the docs for spread below also explain how it replaces the older technique of using apply - that should answer your question

here’s my example with spread ... on the array [65, 66, 67]

String.fromCodePoint(...[65, 66, 67])
// "ABC"

#8

Thanks a lot. That answered my question. The newer spread spread operator seems more simple, but the freecodecamp test environment does not support it yet.


#9

spread is not that new any more - please compare your browser version against the browser compatibility table at the end of every MDN doc - you may just need to update your browser - freecodecamp should support whatever the browser supports