My question is: is there a way anyone came up with for solving the encrypt and decrypt methods that doesn’t involve converting the string into an array and iterating through it?
Bonus question: is it better to do so?
Here’s my solution:
lass ShiftCipher {
constructor(shifter) {
this.shifter = shifter;
}
encrypt(string) {
let upped = string.toUpperCase();
let strArr = [];
for (let i = 0; i < upped.length; i++) {
strArr.push(upped[i]);
}
return strArr
.map((char) => {
if (char.charCodeAt() > 90 || char.charCodeAt() < 65) return char;
if (char.charCodeAt() + this.shifter > 90) {
return String.fromCharCode(char.charCodeAt() + this.shifter - 26);
}
return String.fromCharCode(char.charCodeAt() + this.shifter);
})
.join("");
}
decrypt(string) {
let downed = string.toLowerCase();
let strArr = [];
for (let i = 0; i < downed.length; i++) {
strArr.push(downed[i]);
}
return strArr
.map((char) => {
if (char.charCodeAt() < 97 || char.charCodeAt() > 122) return char;
if (char.charCodeAt() - this.shifter < 97) {
return String.fromCharCode(char.charCodeAt() - this.shifter + 26);
}
return String.fromCharCode(char.charCodeAt() - this.shifter);
})
.join("");
}
}
const twoShift = new ShiftCipher(2);
console.log(twoShift.encrypt('I love to code!'))
console.log(twoShift.decrypt("K <3 OA RWRRA"));
No expert here, from my understanding, string operations are very expensive. They use both memory and clock ticks. Arrays, on the other hand are a data structure intended to be accessed and mutated, while strings can only be accessed, not mutated. That would make their (array) operations more optimized. I can see no reason NOT to use an array and its methods for this type of problem. Moreover it may offer improved readability and it be readily discernible what is going on when we return a year later to review/update this code.
I like your solution where you handled the wrap. It was simpler than mine. One shortcut I took when converting the message into an array of character codes is:
let charCodeArray = [...message]
Where “…” is the spread operator in JS. In this case, the individual characters of the message are spread out as members of the array. Then my for-each loop took care of converting them to character codes and doing the shifting very similar to your code.
So this is what I was able to come up with that managed to avoid the use of Arrays as the original poster questioned.
For each method, I simply set a variable for both upper and lowercase. From there, I run a loop on the string with an additional IF statement to compare the lower and uppercase values.
Only A-Z and a-z will NOT be the same as all spaces and punctuation are identical in upper and lower case.
Code within the IF statement reads:
If uppercase and lowercase are NOT the same (letters), then transcribe the string to Unicode, add the number parameter and then (if necessary) loop the Unicode (adding or subtracting 26).
Else if they are the same (numbers, punctuation, spaces) leave as is.
Either case will then CONCAT all loop outputs to an empty string variable and return that string.
class ShiftCipher {
constructor(number) {
this._number = number;
}
get number() {
return this._number;
}
encrypt(estring) {
let upper = estring.toUpperCase();
let lower = estring.toLowerCase();
let encrypted = '';
for (let i = 0; i < upper.length; i++) {
if (upper[i] !== lower[i]) {
let toUnicode = upper.charCodeAt(i) + this.number;
if (toUnicode > 90) {
toUnicode = toUnicode - 26;
}
let toAlpha = String.fromCharCode(toUnicode);
encrypted = encrypted.concat(toAlpha);
} else {
encrypted = encrypted.concat(upper[i]);
}
}
return encrypted;
}
decrypt(dstring) {
let upper = dstring.toUpperCase();
let lower = dstring.toLowerCase();
let decrypted = '';
for (let i = 0; i < lower.length; i++) {
if (upper[i] !== lower[i]) {
let toUnicode = lower.charCodeAt(i) - this.number;
if (toUnicode < 97) {
toUnicode = toUnicode + 26;
}
let toAlpha = String.fromCharCode(toUnicode);
decrypted = decrypted.concat(toAlpha);
} else {
decrypted = decrypted.concat(lower[i]);
}
}
return decrypted;
}
}
This is my solution. I know there would be better ones. I did not see the given solution though.
class ShiftCipher {
constructor (shift){
this._shift = shift;
}
encrypt(str){
const reg = /[a-zA-Z]/gi;
let valid = str.match(reg);
let newArr = [];
let codeNumber = 0;
for (let i = 0; i < str.length; i++){
if(valid.includes(str[i])){
codeNumber = str.charCodeAt(i) + this._shift;
if(String.fromCharCode(codeNumber).match(reg)){
newArr.push(String.fromCharCode(codeNumber));
} else {
codeNumber = str.charCodeAt(i) - 26 + this._shift;
newArr.push(String.fromCharCode(codeNumber));
}
} else newArr.push(str[i]);
}
return newArr.join("").toUpperCase();
}
decrypt(str){
const reg = /[a-zA-Z]/gi;
let valid = str.match(reg);
let newArr = [];
let codeNumber = 0;
for (let i = 0; i < str.length; i++){
if(valid.includes(str[i])){
codeNumber = str.charCodeAt(i) - this._shift;
if(String.fromCharCode(codeNumber).match(reg)){
newArr.push(String.fromCharCode(codeNumber));
} else {
codeNumber = str.charCodeAt(i) + 26 - this._shift;
newArr.push(String.fromCharCode(codeNumber));
}
} else newArr.push(str[i]);
}
return newArr.join("").toLowerCase();
}
}
const cipher = new ShiftCipher(2);
cipher.encrypt(‘I love to code!’); // returns ‘K NQXG VQ EQFG!’
cipher.decrypt(‘K <3 OA RWRRA’); // returns ‘i <3 my puppy’
console.log(cipher.encrypt(‘I love to code!’));
console.log(cipher.decrypt(‘K <3 OA RWRRA’));