Reputation: 93
how to shift each letter in the given string N places down in the alphabet? Punctuation, spaces, and capitalization should remain intact. For example if the string is "ac" and num is 2 the output should be "ce". What's wrong with my code? It converts letter to ASCII and adds given number then converts from ASCII to letter back. The last line replaces space.
function CaesarCipher(str, num) {
str = str.toLowerCase();
var result = '';
var charcode = 0;
for (i = 0; i < str.length; i++) {
charcode = (str[i].charCodeAt()) + num;
result += (charcode).fromCharCode();
}
return result.replace(charcode.fromCharCode(), ' ');
}
I'm getting
TypeError: charcode.fromCharCode is not a function
Upvotes: 9
Views: 35905
Reputation: 11
The easiest way for me is below: (Code in JavaScript)
function caesarCipherEncryptor(string, key) {
let output = "";
for(let char of string){
let newCode = char.charCodeAt() + key % 26;
if(newCode <= 122){
output += String.fromCharCode(newCode);
} else {
output += String.fromCharCode(96 + (newCode%122));
}
}
return output;
}
Upvotes: 0
Reputation: 1079
One way of solving it as below.
Note: This includes rolling of small, capital and Numeric characters. special symbols renders as it is.
function rotationalCipher(input, rotationFactor) {
// Write your code here
if (!input || rotationFactor < 0 || rotationFactor > 1000000) {
return "";
}
let capitalLetters = [...Array(26).keys()].map((n) => n + 65);
let smallLetters = [...Array(26).keys()].map((n) => n + 97);
let numerics = [...Array(10).keys()].map((n) => n + 48);
return input
.split("")
.map((char) => {
let asciiCode = char.charCodeAt();
if (asciiCode >= 97 && asciiCode <= 122) {
let newAsciiCode = smallLetters.indexOf(asciiCode) + rotationFactor;
return String.fromCharCode(smallLetters[Math.round(newAsciiCode % 26)]);
} else if (asciiCode >= 65 && asciiCode <= 90) {
let newAsciiCode = capitalLetters.indexOf(asciiCode) + rotationFactor;
return String.fromCharCode(
capitalLetters[Math.round(newAsciiCode % 26)]
);
} else if (asciiCode >= 48 && asciiCode <= 57) {
let newAsciiCode = numerics.indexOf(asciiCode) + rotationFactor;
return String.fromCharCode(numerics[Math.round(newAsciiCode % 10)]);
} else {
return char;
}
})
.join("");
}
console.log(rotationalCipher("bB_1c", 10));
console.log(rotationalCipher("bB_1c", 100));
console.log(rotationalCipher("bB_1c", 9));
console.log(rotationalCipher("bB_1cbB_1cbB_1cbB_1cbB_1c", 900));
Upvotes: 0
Reputation: 525
You need to pass an argument to the fromCharCode method using the String object. Try:
function CaesarCipher(str, num) {
// you can comment this line
str = str.toLowerCase();
var result = '';
var charcode = 0;
for (var i = 0; i < str.length; i++) {
charcode = (str[i].charCodeAt()) + num;
result += String.fromCharCode(charcode);
}
return result;
}
console.log(CaesarCipher('test', 2));
I had to modify the return statement, because it was introducing a bug for me
Upvotes: 14
Reputation: 3788
One need to take into account fact of shifting last letters in alphabet back to beginning. Here is my take on that:
var input = "Caesar Cipher";
function CaesarCipher(str, num) {
var alphabet = "abcdefghijklmnopqrstuvwxyz";
var newStr = "";
for (var i = 0; i < str.length; i++) {
var char = str[i],
isUpper = char === char.toUpperCase() ? true : false;
char = char.toLowerCase();
if (alphabet.indexOf(char) > -1) {
var newIndex = alphabet.indexOf(char) + num;
if(newIndex < alphabet.length) {
isUpper ? newStr += alphabet[newIndex].toUpperCase() : newStr += alphabet[newIndex];
} else {
var shiftedIndex = -(alphabet.length - newIndex);
isUpper ? newStr += alphabet[shiftedIndex].toUpperCase() : newStr += alphabet[shiftedIndex];
}
} else {
newStr += char;
}
}
return newStr;
}
console.log(CaesarCipher(input, 20));
Upvotes: 4
Reputation: 3604
Tossing my hat into the fray here, as I just completed this same challenge over on HackerRank.
My solution is similar to the one proposed by @Alexa-905.
k
, e.g., k = 3
, a
becomes d
, z
becomes c
[a-zA-Z]
characters remain the same65-90
are the ranges for A-Z
(uppercase letters)97-122
are the ranges for a-z
(lowercase letters)26
is the number of letters in the alphabetfunction caesarCipher(s, k) {
let result = '';
for (let i = 0; i < s.length; i++) {
const charCode = s.charCodeAt(i);
if (
(charCode < 65 || charCode > 122) ||
(charCode > 90 && charCode < 97)
) {
result += s[i];
} else {
let newCharCode = charCode + Math.ceil(k % 26);
if (charCode >= 97 && newCharCode > 122) {
newCharCode = newCharCode - 122 + 96;
}
if (charCode <= 90 && newCharCode > 90) {
newCharCode = newCharCode - 90 + 64;
}
result += String.fromCharCode(newCharCode);
}
}
console.log(result);
return result
}
caesarCipher('F rpb Jxqe.zbfi(h%26) ql zrq altk lk olqxqflkp', 3);
caesarCipher('26 rb cqn wdvkna xo unccnab rw cqn juyqjknc', 17)
caesarCipher('65-90 mdq ftq dmzsqe rad M-L (gbbqdomeq xqffqde)', 534);
caesarCipher('97-122 kbo dro bkxqoc pyb k-j (vygobmkco voddobc)', 425974);
caesarCipher('Aopz jvkl ybuz ha 454,064 vwlyhapvuz wly zljvuk!', 19);
caesarCipher('myyux://oxujwk.htr/hfjxfw-nk-ax-wjljc/1', 141235435141);
Upvotes: 3
Reputation: 60
function caesarCipher(s, k) {
var n = 26; // alphabet letters amount
if (k < 0) {
return caesarCipher(s, k + n);
}
return s.split('')
.map(function (c) {
if (c.match(/[a-z]/i)) {
var code = c.charCodeAt();
var shift = code >= 65 && code <= 90 ? 65 : code >= 97 && code <= 122 ? 97 : 0;
return String.fromCharCode(((code - shift + k) % n) + shift);
}
return c;
}).join('');
}
Use String.charCodeAt() to convert the English character to ASCII.
Use String.fromCharCode() to convert ASCII to English character.
Try caesarCipher("always-look-on-the-bright-side-of-life", 10)
=> "kvgkic-vyyu-yx-dro-lbsqrd-csno-yp-vspo"
caesarCipher("kvgkic-vyyu-yx-dro-lbsqrd-csno-yp-vspo", -10)
=> "always-look-on-the-bright-side-of-life"
Upvotes: 3
Reputation: 528
I know this is a bit old but I thought I'd give it a go. Here's my take on it.
It accounts for uppercase and lowercase. It can also shift either forwards or backwards any amount!
function shift(str, n) {
var shifted = '';
n = n%26;
for (var i = 0; i < str.length; i++) {
let code = str[i].charCodeAt();
let capital = (code > 64 && code < 91) ? true : false;
if (code < (capital?65:97) || code > (capital?90:122) || n == 0) {
shifted += str[i];
continue;
}
if (n > 0) {
if (code > (capital?90:122)-n) {
code = n + code - 26;
} else {
code += n;
}
} else {
if (code < (capital?65:97)-n) {
code = code + n + 26;
} else {
code += n;
}
}
shifted += String.fromCharCode(code);
}
return shifted;
}
console.log(shift('Ebiil, Tloia!', 3));
Upvotes: 1
Reputation: 872
That's my solution
function rot13(str) {
var result = str.split("")
.map(function(val) {
var letterKey = val.charCodeAt() - 13;
if(letterKey < 65){
letterKey = 90 - (65 - letterKey - 1);
}
console.log(letterKey);
return String.fromCharCode(letterKey);
})
.join("");
return result;
}
Upvotes: 1
Reputation: 111
Try:
result += String.fromCharCode(charcode)
Taken from: http://www.w3schools.com/jsref/jsref_fromCharCode.asp
Upvotes: 0
Reputation: 4864
The fromCharCode function doesn't operate on strings, it operates on the global String
object like so String.fromCharCode(65, 66, 67); // "ABC"
ripped off straight from the docs.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCharCode
Upvotes: 1