I'm completely stuck here. Here's the problem I'm solving:
A shift cipher takes a plain text message and shifts each letter forward in the alphabet by a given number. For example, a shift cipher with a shift of 1 would turn the string 'hello' to 'ifmmp'.
Example:
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'
Here's my code:
// Write class below
class ShiftCipher {
constructor(num) {
this.num = num;
}
encrypt(str) {
const lowCase = str.toLowerCase();
const alphabet = 'abcdefghijklmnopqrstuvwxyz';
let encrypted = '';
for(let i = 0; i < lowCase.length; i++) {
if(!alphabet.includes(lowCase[i])) {
encrypted += lowCase[i];
}
for(let j = 0; j < alphabet.length; j++) {
if(lowCase[i] == alphabet[j]) {
encrypted += alphabet[j + this.num].toUpperCase();
}
}
}
console.log(encrypted);
}
}
const cipher = new ShiftCipher(2);
cipher.encrypt('I love to codez!');
Last two lines is for testing my method. Everything works fine until iteration doesn't come to an end of alphabet. I added z to the end to test it working with last letter of alphabet. It should start over from alphabet so when I call Z with 2 it should return B but of course I get error because string ends and I'm unable to make it start over.
I've googled around and understand that continue might be solution here but I have still failed to use it in my code.
Cheers!
The problem seems to be this line:
encrypted += alphabet[j + this.num].toUpperCase();
When you reach the end of the alphabet, the letter z, j + this.num will be greater than the length of the alphabet. Indexing the array out of range will produce undefined so your code breaks.
Add a wrap-around like this:
encrypted += alphabet[(j + this.num) % alphabet.length].toUpperCase();
Related
This is my first post so I hope im doing this correctly.
I am taking a coding class and we were asked to make a piece of code that will ask for the input of a phrase, and will return in the console that phrase with the capital letters moved to the front, but still in the same order. Then print to the console this reordered phrase. (We aren't allowed to use arrays)
For example:
Inputting "HeLLoTherE" would return "HLLTEeoher"
However the problem is im having issues understanding how to write this code. How can I make the code select these capital letters and move them to the front? using .toUpperCase()? How can i make that select the letter and move it in front of the rest?
If someone could show me an example of how this is done and explain it a little i would greatly appreciate it :)
You might just start with a the most straight forward algorithm to get something working.
let value = "HeLLoTherE";
let result = "";
for (let char of value) {
if (char >= "A" && char <= "Z") {
result += char;
}
}
for (let char of value) {
if (char >= "a" && char <= "z") {
result += char;
}
}
console.log(result);
You could then consolidate the 2 loops by combining the conditions.
let value = "HeLLoTherE";
let upper = "";
let lower = "";
for (let char of value) {
if (char >= "A" && char <= "Z") {
upper += char;
} else if (char >= "a" && char <= "z") {
lower += char;
}
}
console.log(upper + lower);
Another way of solving this would be to use regex.
var value = "HeLLoTherE";
var upper = value.replace(/[^A-Z]*/g, "");
var lower = value.replace(/[^a-z]*/g, "");
console.log(upper + lower);
Well, you are not able to use arrays, which makes it a little bit difficult, however you can still do sommething.
Although I'm using a for loop, I'm not actually using arrays. Since strings allows the [] operator, you can use an index to select each character of the string and check if it's lowercase or uppercase.
In addition, you said you need to mantain the order of uppercase letters, so you couldn't just do newStr = upper + newStr, because it would revert the original order. So, I used the string.prototype.substring() to insert the uppercase character where it should be.
const str = "HeLLoTherE";
const moveUpperToFront = (target) => {
// Strings are immutable in js, so you cannot move one character
// to the front without using a new string.
let newStr = "";
// Number of uppercase letters that appeared.
// It's necessary because you need to mantain the original order
let upperNumber = 0;
// Iterate each character from beginning
for (let i = 0; i < str.length; ++i) {
// Is there an uppercase letter?
if (str[i].charCodeAt() >= 65 && str[i].charCodeAt() <= 90) {
newStr =
newStr.substring(0, upperNumber) +
str[i] +
newStr.substring(upperNumber, newStr.length);
++upperNumber;
}
// No uppercase letter?
else
newStr += str[i];
}
return newStr;
};
console.log(moveUpperToFront(str));
Following a solution which uses a for...of loop to iterate the input. It splits the input into capital and lowercase literals and then merges back together:
const exampleLiteral = 'HeLLoTherE';
const isUppercase = (literal) => literal === literal.toUpperCase() && literal !== literal.toLowerCase();
const prefixCapitalLetters = (literal) => {
let capitalLetters = '';
let lowerLetters = '';
for (let letter of literal) {
if(isUppercase(letter)) {
capitalLetters = capitalLetters.concat(letter);
continue;
}
lowerLetters = lowerLetters.concat(letter);
};
return capitalLetters+lowerLetters;
}
console.log(prefixCapitalLetters(exampleLiteral));
This is really not a very hard problem:
function rearrange(str) {
let result = "";
for (let c of str)
if (c >= 'A' && c <= 'Z')
result += c;
for (let c of str)
if (c < 'A' || c > 'Z')
result += c;
return result;
}
console.log(rearrange("Hello World, It Is A Beautiful Morning!"));
Find the upper-case characters, and add them to a result string. Then go back and find the other characters, and add them at the end. By looping through without any sorting, just simple iteration from start to finish, the order is preserved (other than the upper-case stuff).
The truly hard part of this would be coming up with a way to detect "upper-case" letters across all of Unicode. Some languages (well, orthographies) don't have the concept at all. JavaScript has ways that are more and less convenient to deal with that, but I suspect for the classroom material the OP has available so far, given the nature of the original question, such regex trickery would probably be inappropriate for an answer.
This answer tries to achieve the desired objective without using "arrays". It does use back-ticks, but that can be replaced with a simple string-concatenation if required.
Code Snippet
// move upper-case letters while
// keeping relative order same
const capsWithOrder = str => {
// initialize result variables
let capsOnly = "", restAll = "";
// iterate over the given string input
for (let i = 0; i < str.length; i++) {
// if character at index "i" is upper-case
// then, concatenate character to "capsOnly"
// else, concatenate to "restAll"
if (str[i] === str[i].toUpperCase()) capsOnly += str[i];
else restAll += str[i];
};
// after iterating over all characters in string-input
// return capsOnly concatenated with restAll
return `${capsOnly}${restAll}`;
};
console.log(capsWithOrder("HeLLoTherE"));
Explanation
Inline comments added in the snippet above.
Something like this
const string1 = 'HeLLoTherE'
const transform = string => {
const lower = string.split('').filter(c => c.charCodeAt() > 'a'.charCodeAt())
const upper = string.split('').filter(c => c.charCodeAt() < 'Z'.charCodeAt())
return [...upper, ...lower].join('')
}
console.log(transform(string1))
I think that must be work.
const sort = [
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''),
'abcdefghijklmnopqrstuvwxyz'.split('')
]
function listByValue(string) {
string = [...string];
let ret = [];
for (let i in sort)
ret = [...ret,...string.filter(e=>sort[i].includes(e))];
return ret.join('')
}
This project is in javascript. I need to make sure the output retains spaces found in the string that is inputted into the function. The test I am trying to pass is calling the function for the term "hello world" with a shift of 13 letters. From this code, the result is "uryybjbeyq" and "uryyb jbeyq" is expected. I have identified I need an if statement which I have included already, but not sure what command I should include before the continue keyword that will insert the space needed. I am a beginner and this is only my 3rd project so any assistance would be appreciated. Please find the corresponding code below.
function caesarCypher(string, num){
// line below is the encrypted string we will return from the function
const letters = 'abcdefghijklmnopqrstuvwxyz';
let encryptStr = ""
// loop through every character in the inputted string
for(let i = 0; i < string.length; i++){
// line below will look up index of char in alphabet
let char = string[i];
/* if statement below is attempting to identify the space in the original string and then add a command that will add a space to the encrypted string then continue to work through the rest of the input */
if (char === " ") {
//need something to put on this line to insert space;
continue;
}
let index = letters.indexOf(char);
// index + num below will give us the letter 7 spots over
let newIndex = index + num;
// if statement below makes the function loop back around
if (newIndex > 26) {
newIndex = newIndex - 26;
}
let newChar = letters[newIndex];
encryptStr += newChar;
}
return encryptStr;
}
/* invoke the function with these parameters to pass the test-- expected result is 'uryyb jbeyq'*/
caesarCypher("hello world", 13)
You can add the white space like this:
encryptStr += " ";
I tried your code and I ran into an error... All letters were the same. Here is how I did it:
function caesarCypher(string, num){
let encryptStr = "";
for(let i = 0; i < string.length; i++){
let char = string[i];
if (char === " ") {
encryptStr += " "; //This adds a white space.
continue;
}
// If you want to keep the case of a letter, skip the
// "toLowerCase()" and extend the condition below.
let asciiCode = string.toLowerCase().charCodeAt(i) + num;
if(asciiCode > 122) {
asciiCode -= 26;
}
encryptStr += String.fromCharCode(asciiCode);
}
return encryptStr;
}
I know that there is a lot of information on here about regex's, but I really cant seem to get this to work. I have a for loop, looping through an array. I want to see if the current index of the array is not equal to a group of numbers (32-64). I have declared a variable let patt which holds the regex that I think should work, but I cant figure out the syntax to check against it. I was sure it would be .match, but again, not sure how to word !.match
any advise, solutions or even a point in the direction of a good JS regex tutorial would be much appreciated!
class ShiftCipher{
constructor(shift){
this.shift = shift;
}
encrypt(string){
let up = string.toUpperCase(); //convert string to uppercase
let uni = [];
let newArr = [];
let i, j;
let patt = /[32-64]/g; //think this is wrong...
for(i = 0; i < up.length; i++){
uni.push(up.charCodeAt(i)) //push converted chars as unicodes to new array
if(uni[i] != 32){ // if unicode is 32 (space) leave as is. //I want a regex here for != unicode 32 - 64
uni[i] += this.shift; // shift unicode by parent class specification (shift)
}
}
for(j = 0; j < up.length; j++){
if(uni[j] > 90){ // if unicode is higher than 90(z)..
uni[j] -= 26; // loop back round starting at (a).
}
let text = String.fromCharCode(uni[j]); //convert from unicode to string
newArr.push(text); //push string to array
}
let final = newArr.join(''); //join array elements(as a string) and store in final
console.log(final);
}
}
const cipher = new ShiftCipher(2);
cipher.encrypt('I love to code z!');
I want to see if the current index of the array is not equal to a group of numbers (32-64)
Char codes are numbers. Try numerical comparisons.
for (i = 0; i < up.length; i++) {
if (up.charCodeAt(i) >= 32 && up.charCodeAt(i) <= 64) {
// ...
}
}
But technically, you can use regex too. Creating a character range from char codes works like this:
var patt = /[\x20-\x40]/; // hex 20 = decimal 32, hex 40 == decimal 64
for (i = 0; i < up.length; i++) {
if (patt.test(up.charAt(i)) {
// ...
}
}
Note that this uses .charAt().
The /[\x20-\x40]/ is interpreted as if you had written the actual characters, so in this case it's equivalent to /[ -#]/.
As your wraparound constant is 26, the length of the English alphabet, one could assume that you want to alter only the letters, and then the magical regexp is [A-Z]:
class ShiftCipher {
constructor(shift) {
this.shift = shift;
}
encrypt(string) {
return string.toUpperCase().replaceAll(/[A-Z]/g, char => {
let code = char.charCodeAt(0) + this.shift;
if(code>90)
code-=26;
return String.fromCharCode(code);
});
}
}
const cipher = new ShiftCipher(2);
console.log(cipher.encrypt('I love to code z!'));
I made a little script for custom encryption and decryption algorithms, which are based on Caesar cipher and transcription cipher.
First a little bit of background for explanation on how it should work. Assume a message you want to encrypt before sending. You apply Caesar cipher to it, which is shift each letter by 3 positions in alphabet to right. Then you take that encrypted text and divide it to sections by number of letters your key has. Let's say your message has n letters, and your key has m letters. Then your message should be broken up to n/m sections (rounding up or ceiling), each one of m letters. If the message length isn't divisible by the number of letters in key, then it has to be padded to fill in missing letters by letter A. Then given by the key, you transpose the columns based on the position of that particular letter of key corresponding to column number in alphabet. So if your key is let's say LEAK, then columns have to be transposed based on the position as follows: 3241, because 1234 corresponds to AEKL (sorted by alphabetical order). Then this transposed matrix is then concatenated back to the corresponding string, which then can be sent. Decipher is basically the same process reversed in order → You receive a message, and you know the key. You parcel it to columns and then transpose the columns in order to correspond to alphabetical order of the letters from key, concatenate it back, and then run through reverse Caesar cipher (shift letters by 3 positions in alphabet to the left). You may get a few X letters at the end, that doesn't actually matter.
Now to my issue: I wrote a little Javascript program for it, it is in fact a module, and I also have a test script for it to see how it works. But it doesn't work correcly. The transposition is wrong, which results in deciphered text being malformed. I know the deciphered text as I've done this algorithm manually before writing that script and I know the outcome it should have.
This is the module:
module.exports = {
decrypt: (message, key) => {
if(message.length % key.length != 0) {
throw new Error(`Lenght of message is not divisible by lenght of the key! ${message.length} is not divisible by ${key.length}!`);
}
let key_array_unsorted = key.split('');
let key_array_sorted = key.split('').sort();
let message_matrix = [];
for(i = 0; i < message.length / key.length; ++i) {
let quartet = [];
for(j = 0; j < key.length; ++j) {
quartet.push(message.charAt(i*key.length + j));
}
message_matrix.push(quartet);
}
let message_matrix_shuffled = [];
message_matrix.forEach(quartet => {
let quartet_shuffled = [];
for(i = 0; i < key.length; ++i) {
for(j = 0; j < key.length; ++j) {
if(key_array_unsorted[i] == key_array_sorted[j]) {
quartet_shuffled.push(quartet[j]);
}
}
}
message_matrix_shuffled.push(quartet_shuffled);
});
let message_quartets = [];
message_matrix_shuffled.forEach(quartet => {message_quartets.push(quartet.join(''))});
let message_caesar = message_quartets.join('');
let message_deciphered = "";
for(i = 0; i < message_caesar.length; ++i) {
let charcode = message_caesar.charCodeAt(i);
let alphanum = charcode - 65;
let alphanum_new = (alphanum + 23) % 26;
let charcode_new = alphanum_new + 65;
message_deciphered += String.fromCharCode(charcode_new);
}
return message_deciphered;
},
encrypt: (message, key) => {
let message_caesar = "";
for(i = 0; i < message.length; ++i) {
let charcode = message.charCodeAt(i);
let alphanum = charcode - 65;
let alphanum_new = (alphanum + 3) % 26;
let charcode_new = alphanum_new + 65;
message_caesar += String.fromCharCode(charcode_new);
}
for(i = 0; i <= Math.ceil(message_caesar.length / key.length) * key.length - message_caesar.length; ++i) {
message_caesar += "A";
}
let key_array_unsorted = key.split('');
let key_array_sorted = key.split('').sort();
let message_matrix = [];
for(i = 0; i < message_caesar.length / key.length; ++i) {
let quartet = [];
for(j = 0; j < key.length; ++j) {
quartet.push(message_caesar.charAt(i*key.length + j));
}
message_matrix.push(quartet);
}
let message_matrix_shuffled = [];
message_matrix.forEach(quartet => {
let quartet_shuffled = [];
for(i = 0; i < key.length; ++i) {
for(j = 0; j < key.length; ++j) {
if(key_array_sorted[i] == key_array_unsorted[j]) {
quartet_shuffled.push(quartet[j]);
}
}
}
message_matrix_shuffled.push(quartet_shuffled);
});
let message_quartets = [];
message_matrix_shuffled.forEach(quartet => {message_quartets.push(quartet.join(''))});
let message_ciphered = message_quartets.join('');
return message_ciphered;
}
}
And this is the test script:
const cipher = require('./cipher');
let message = "HGYRDGQCREGLDYQROXRHABAK";
let key = "OMYL";
console.log(`Received message: ${message}`);
console.log(`Known passphrase: ${key}`);
let message_deciphered = cipher.decrypt(message, key);
console.log(`Deciphered message: ${message_deciphered}`);
let message_encrypted = cipher.encrypt(message_deciphered, key);
console.log(`Control encryption: ${message_encrypted}`);
The module and the test scripts are in the same folder.
This is how the output should have been:
Received message: HGYRDGQCREGLDYQROXRHABAK
Known passphrase: OMYL
Deciphered message: ODEVZDANIBODOVANEULOHYXX
Control encryption: HGYRDGQCREGLDYQROXRHABAK
And this is current output:
Received message: HGYRDGQCREGLDYQROXRHABAK
Known passphrase: OMYL
Deciphered message: VDOENDZADBIONVOAOUELXYHX
Control encryption: HGYRDGQCREGLDYQROXRHABAK
Now, I know for sure that the key's letters are sorted correctly and that's not the cause of the incorrect transcription, I actually looked for the key's letters being sorted correctly and it's okay. OMYL does in fact sort correctly to LMOY.
The issue has to be in the transcription itself, where it doesn't correspond to the alphabetical order of the key. The thing is, I can't for some reason spot a mistake, if there is any. I guess Javascript isn't really much good language to use for such thing, but it is fairly easy and doesn't require compilation. All I wanted to do is make myself a gadget or tool to make quick solver for my assignment, which I get in Monday and I already know the topic for that assignment, which is that cipher.
Maybe I am doing it wrong, maybe I shouldn't actually use the key letters to be compared and instead build a sort of shuffle map for the transcription based on the alphabetical order of the key letters (and of course the order of steps - encryption or decryption). Which is something I don't know how to do, unfortunately :(
Based on the algorithm given by the OP in the chat, the code word sequencing is wrong
Compare sorted sequence with unsorted sequence instead of the other way
Replace key_array_unsorted[i] == key_array_sorted[j] with key_array_sorted[i] == key_array_unsorted[j]
class VigenèreCipher {
constructor(key, abc) {
this.encode = function (str) {
//split the string into an array
let arr = abc.split("");
let keyValue = [];
for (let i = 0; i < key.length; i++) {
//finding the letter(key) value and push it to key value
keyValue.push(arr.indexOf(key[i]));
}
let redacted = "";
let pointer = 0;
for (let i = 0; i < str.length; i++) {
if (arr.includes(str[i])) {
let shift = arr.indexOf(str[i]) + keyValue[pointer];
if (shift >= 26) {
redacted += arr[shift - 26];
} else {
redacted += arr[shift];
}
//debugging code
console.log(
`string: ${str[i]}`,
`shift: ${shift - 26}`,
`shiftTo ${arr[shift]}`,
`pointer: ${pointer}`,
`KeyValue: ${keyValue[pointer]}`
);
pointer += 1;
} else {
pointer = 0;
redacted += str[i];
}
if (pointer >= keyValue.length) {
pointer = 0;
}
}
//console.log(keyValue);
console.log(`redacted: ${redacted}`);
return redacted
};
this.decode = function (str) {
let arr = abc.split("");
let keyValue = [];
for (let i = 0; i < key.length; i++) {
//finding the letter(key) value and push it to key value
keyValue.push(arr.indexOf(key[i]));
}
let decoded = "";
let pointer = 0;
for (let i = 0; i < str.length; i++) {
if (arr.includes(str[i])) {
let shift = arr.indexOf(str[i]) - keyValue[pointer];
if (shift < 0) {
decoded += arr[26 - Math.abs((arr.indexOf(str[i]) - keyValue[pointer]))];
} else {
decoded += arr[Math.abs((arr.indexOf(str[i]) - keyValue[pointer]))];
}
//debugging code
console.log(
`string: ${str[i]} `,
`shift: ${arr.indexOf(str[i]) - keyValue[pointer]} `,
`shiftTo ${arr[arr.indexOf(str[i]) - keyValue[pointer]]} `,
`pointer: ${pointer} `,
`KeyValue: ${keyValue[pointer]} `,
`arrindex: ${arr.indexOf(str[i])} `,
);
pointer += 1;
} else {
pointer = 0;
decoded += str[i];
}
if (pointer >= keyValue.length) {
pointer = 0;
}
}
//console.log(keyValue);
console.log(`decode: ${decoded}`);
return decoded
};
};
}
The Vigenère cipher is a method of encrypting alphabetic text by using a series of different
Caesar ciphers based on the letters of a keyword. It is a simple form of polyalphabeticsubstitution.
In a Caesar cipher, each letter of the alphabet is shifted along some number of places; for example,in a Caesar cipher of shift 3, A would become D, B would become E, Y would become B and so on. The Vigenère cipher consists of several Caesar ciphers in sequence with different shift values. Assume the key is repeated for the length of the text, character by character. Note that some implementations repeat the key over characters only if they are part of the alphabet -- this is not the case here.The shift is derived by applying a Caesar shift to a character with the corresponding index of the key in the alphabet.
**ar abc, key;
abc = "abcdefghijklmnopqrstuvwxyz";
key = "password"
c = new VigenèreCipher(key, abc);
Test.assertEquals(c.encode('codewars'), 'rovwsoiv');
Test.assertEquals(c.decode('rovwsoiv'), 'codewars');
Test.assertEquals(c.encode('waffles'), 'laxxhsj');
Test.assertEquals(c.decode('laxxhsj'), 'waffles');
Test.assertEquals(c.encode('CODEWARS'), 'CODEWARS');
Test.assertEquals(c.decode('CODEWARS'), 'CODEWARS');**
**Expected: 'xt\'k o vwixl qzswej!', instead got: 'xt\'h p hhaxp rihzaf!'
Expected: 'it\'s a shift cipher!', instead got: 'it\'v z gwqfp bzaeiv!'**
**Expected: 'ドオカセガヨゴザキアニ', instead got: 'ドテタヒガォゴザキノイ'
Expected: 'ドモアリガトゴザイマス', instead got: 'ドタシェガホゴザイィス'**
**The code solve most problem but won't solve those any idea whats going on or how to fix it?**
The information given in the post states
... Note that some implementations repeat the key over characters only if they are part of the alphabet -- this is not the case here. ...
To achieve this you increment the pointer and/or set it to zero after processing each and every character. You could put the unconditional update of pointer immediately before the end of loop, removing other pointer updates, like
...
pointer += 1;
if( pointer >= keyValue.length) {
pointer = 0
}
} // end of for loop
or by calculating it directly as
pointer = (pointer + 1) % keyValue.length;
This gets the code to encode "it's a shift cipher!" as "xt'k o vwixl qzswej!" as expected, and decode that result back to the original without error (after fixing pointer updating in both encode and decode of course).
You reset the pointer to zero in the else when you detect a character that is not in the alphabet. In general, you only increase the "pointer" within the key if you encrypt and otherwise you leave it alone, you don't reset it.