-
-
Save EvanHahn/2587465 to your computer and use it in GitHub Desktop.
/* | |
JavaScript Caesar shift | |
by Evan Hahn (evanhahn.com) | |
"Encrypt" like this: | |
caesarShift('Attack at dawn!', 12); // Returns "Mffmow mf pmiz!" | |
And "decrypt" like this: | |
caesarShift('Mffmow mf pmiz!', -12); // Returns "Attack at dawn!" | |
For simplicity, only works with ASCII characters. | |
* * * * * * * * * * * * | |
This is free and unencumbered software released into the public domain. | |
Anyone is free to copy, modify, publish, use, compile, sell, or distribute | |
this software, either in source code form or as a compiled binary, for any | |
purpose, commercial or non-commercial, and by any means. | |
In jurisdictions that recognize copyright laws, the author or authors of this | |
software dedicate any and all copyright interest in the software to the public | |
domain. We make this dedication for the benefit of the public at large and to | |
the detriment of our heirs and successors. We intend this dedication to be an | |
overt act of relinquishment in perpetuity of all present and future rights to | |
this software under copyright law. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | |
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
For more information, please refer to <https://unlicense.org/> | |
*/ | |
var caesarShift = function (str, amount) { | |
// Wrap the amount | |
if (amount < 0) { | |
return caesarShift(str, amount + 26); | |
} | |
// Make an output variable | |
var output = ""; | |
// Go through each character | |
for (var i = 0; i < str.length; i++) { | |
// Get the character we'll be appending | |
var c = str[i]; | |
// If it's a letter... | |
if (c.match(/[a-z]/i)) { | |
// Get its code | |
var code = str.charCodeAt(i); | |
// Uppercase letters | |
if (code >= 65 && code <= 90) { | |
c = String.fromCharCode(((code - 65 + amount) % 26) + 65); | |
} | |
// Lowercase letters | |
else if (code >= 97 && code <= 122) { | |
c = String.fromCharCode(((code - 97 + amount) % 26) + 97); | |
} | |
} | |
// Append | |
output += c; | |
} | |
// All done! | |
return output; | |
}; |
I did not understood this expression
"((code - 65 + amount) % 26) + 65)" on line no 76 can you help me out.
thanks for giving me time .
There is only 26 characters in ascii, if you don't mod encrypt string by 26, encyrpted string will fall outside ascii range. for example ç => % or z = İ etc.
If you mod it by 26, encrypted string will be only ascii too, so it is guarentied it'll be human-readable. If you don't care about human readability of encrypted string, you may take it as optional.
const caesar = (text, shift) => {
return String.fromCharCode(
...text.split('').map(char => (char.charCodeAt() + shift)),
);
};
Btw, 65 and 95 is for ascii range of lowercase and uppercase characters.
@alimertcakar Good point. I've added a comment mentioning that this is ASCII-only.
I understand all of this, but why should i divide by 26? I considered manually, some garbage comes out.
I understand all of this, but why should i divide by 26? I considered manually, some garbage comes out.
I also don't understand this part
I wrote this a long time ago and don't have time to help debug this, sadly.
const caesar = (text, shift) => {
return String.fromCharCode(
...text.split('').map(char => ((char.charCodeAt() - 65 + shift) % 26) + 65),
);
};
caesar("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 13) // NOPQRSTUVWXYZABCDEFGHIJKLM
2020 Typescript Version:
// Caesar Cipher
const caesarCipher = (string: string, shift: number) => {
// Alphabet
const alphabet: string = '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));
CDEFGHIJKLMNOPQRSTUVWXYZAB
Example #2:
console.log(caesarCipher('GUR DHVPX OEBJA QBT WHZCRQ BIRE GUR YNML SBK.', 26 + 13));
THE QUICK BROWN DOG JUMPED OVER THE LAZY FOX.
Thank you! I've been struggling a lot with this exercise. Your code is wonderfully clean and instructive, I managed to get mine working thanks to you!
@mosemet, your solution works only with min characters, a more complete solution :
function shift(letter, k, code) {
return String.fromCharCode(((letter.charCodeAt() - code + k) % 26) + code);
}
function caesarCipher(s, k) {
return s.replace(/[a-z]/g, char => shift(char, k, 97)).replace(/[A-Z]/g, char => shift(char, k, 65));
}
-------------------------- OR --------------------------
function isCharacterAMinLetter(char) {
return (/[a-z]/).test(char)
}
function isCharacterAMajLetter(char) {
return (/[A-Z]/).test(char)
}
function shift(letter, k, code) {
return String.fromCharCode(((letter.charCodeAt() - code + k) % 26) + code);
}
return s.replace(/[A-Za-z]/g, char => {
// check if min letter
if (isCharacterAMinLetter(char)) {
return shift(char, k, 97);
}
// check if maj letter
else if (isCharacterAMajLetter(char)) {
return shift(char, k, 65);
}
});
It's working perfectly. Thanks Evan for the awesome solution!!!
function rotateAlphabet(text, noOfChars = 0){
const n = noOfChars % text.length;
return text.slice(n) + text.slice(0, n);
}
function convertText(string, noOfChars = 0) {
const alphabetLowercase = 'abcdefghijklmnopqrstuvwxyz'
const alphabetRotatedLowercase = rotateAlphabet(alphabetLowercase, noOfChars)
const alphabetUppercase = alphabetLowercase.toUpperCase()
const alphabetRotatedUppercase = rotateAlphabet(alphabetUppercase, noOfChars)
let arrayResult = []
let index = 0
for (let i = 0; i < string.length; i++) {
// if character is NOT alphanumeric
if (! /^[a-zA-Z]+$/.test(string[i])) {
arrayResult.push(string[i])
} else if (string[i] == string[i].toLowerCase()) {
// if character is lowercase
index = (alphabetLowercase.indexOf(string[i]))
arrayResult.push((alphabetRotatedLowercase[index]))
} else if (string[i] == string[i].toUpperCase()) {
// else if character is uppercase
index = (alphabetUppercase.indexOf(string[i]))
arrayResult.push((alphabetRotatedUppercase[index]))
}
}
return arrayResult.join('')
}
@mosemet, your solution works only with min characters, a more complete solution :
function shift(letter, k, code) { return String.fromCharCode(((letter.charCodeAt() - code + k) % 26) + code); } function caesarCipher(s, k) { return s.replace(/[a-z]/g, char => shift(char, k, 97)).replace(/[A-Z]/g, char => shift(char, k, 65)); }-------------------------- OR --------------------------
function isCharacterAMinLetter(char) { return (/[a-z]/).test(char) } function isCharacterAMajLetter(char) { return (/[A-Z]/).test(char) } function shift(letter, k, code) { return String.fromCharCode(((letter.charCodeAt() - code + k) % 26) + code); } return s.replace(/[A-Za-z]/g, char => { // check if min letter if (isCharacterAMinLetter(char)) { return shift(char, k, 97); } // check if maj letter else if (isCharacterAMajLetter(char)) { return shift(char, k, 65); } });
not safe to use, z
will be decoded to ` instead of a
Or in ES: