Encryption... almost works - javascript

I wrote a simple script for a website called Codewars (here: https://www.codewars.com/kata/57814d79a56c88e3e0000786). The purpose of the function was to encrypt a string such that every second character would appear first, and then the rest of them. I tested many random strings of text; it worked for a while. But then, I tested a specific case with 17 characters: "maybe do i really", and it resulted in a character being dropped (notably a space). Initially, I thought the issue was that the .join method didn't allow a double space in a row, so I attempted to make my own function to mimic its functionality: it did not solve the problem. Could anyone answer why this specific string loses a character and returns a wrong encryption? My jsfiddle is here: https://jsfiddle.net/MCBlastoise/fwz62j2g/
Edit: I neglected to mention that it runs a certain number of times based on parameter n, encrypting the string multiple times per that value.
And my code is here:
function encrypt(text, n) {
if (n <= 0 || isNaN(n) === true || text === "" || text === null) {
return text;
}
else {
for (i = 1; i <= n; i++) {
if (i > 1) {
text = encryptedString;
}
var evenChars = [];
var oddChars = [];
for (j = 0; j < text.length; j++) {
if (j % 2 === 0) {
evenChars.push(text.charAt(j));
}
else {
oddChars.push(text.charAt(j));
}
}
var encryptedString = oddChars.join("") + evenChars.join("");
}
return encryptedString;
}
}
function decrypt(encryptedText, n) {
if (n <= 0 || encryptedText === "" || encryptedText === null) {
return encryptedText;
}
else {
for (i = 1; i <= n; i++) {
if (i > 1) {
encryptedText = decryptedString;
}
var oddChars = [];
var evenChars = [];
for (j = 0; j < encryptedText.length; j++) {
if (j < Math.floor(encryptedText.length / 2)) {
oddChars.push(encryptedText.charAt(j));
}
else {
evenChars.push(encryptedText.charAt(j));
}
}
var convertedChars = []
for (k = 0; k < evenChars.length; k++) {
convertedChars.push(evenChars[k]);
convertedChars.push(oddChars[k]);
}
var decryptedString = convertedChars.join("");
}
return decryptedString;
}
}
document.getElementById("text").innerHTML = encrypt("maybe do i really", 1);
document.getElementById("text2").innerHTML = decrypt("ab oiralmyed ely", 1)
<p id="text"></p>
<p id="text2"></p>

Nothing wrong with the code itself. Basically HTML doesn't allow 2 or more spaces. You can use <pre> tag for the case like this.
document.getElementById("text").innerHTML = "<pre>" + encrypt("maybe do i really", 1) + "</pre>";

Related

Search if a string contains a substring in Javascript (partial search)

Yes I know we can use indexOf and includes or a regular expression to find weather a string is present in another string.
But we have a different requirement. We would like indexOf or includes function to return true even if partial string is matched not the whole world. Let me provide an example.
Let's say my username is "Animation". The string the I am entering is "sssrtAnimyt5678". Now as the string "sssrtAnimyt5678" contains "Anim" which is present in "Animation" we want the function to return true.
The problem with indexOf, includes and regular expression is it tries to find the whole word "Animation" but not the partial word "Anim". I even used KMP Algorithm and found out that even KMP searches for "Animation" not "Anim". Below is the implementation of KMP in Javascript.
var makeKMPTable = function(word) {
if(Object.prototype.toString.call(word) == '[object String]' ) {
word = word.split('');
}
var results = [];
var pos = 2;
var cnd = 0;
results[0] = -1;
results[1] = 0;
while (pos < word.length) {
if (word[pos - 1] == word[cnd]) {
cnd++;
results[pos] = cnd;
pos++;
} else if (cnd > 0) {
cnd = results[cnd];
} else {
results[pos] = 0;
pos++;
}
}
return results;
};
var KMPSearch = function(string, word) {
if(Object.prototype.toString.call(string) == '[object String]' ) {
string = string.split('');
}
if(Object.prototype.toString.call(word) == '[object String]' ) {
word = word.split('');
}
var index = -1;
var m = 0;
var i = 0;
var T = makeKMPTable(word);
while (m + i < string.length) {
if (word[i] == string[m + i]) {
if (i == word.length - 1) {
return m;
}
i++;
} else {
m = m + i - T[i];
if (T[i] > -1) {
i = T[i];
} else {
i = 0;
}
}
}
return index;
};
console.log(KMPSearch("sssrtAnimyt5678", "Animation")); // returns -1
So I would like to know if such kind of partial search is possible and if anybody can point me to such implementation details or algorithm it would be helpful.
Thanks in Advance.
Just check any possible substring.
const
hasCommon = (a, b) => {
for (let i = 0; i < a.length; i++) {
for (let j = i + 1; j <= a.length; j++) {
if (b.includes(a.slice(i, j))) return true;
}
}
return false;
};
console.log(hasCommon('Animation', 'sssrtAnimyt5678'));

How do i return the result of all loops in javascript?

I am trying to insert dashes ('-') between each two odd numbers and insert asterisks ('*') between each two even numbers, but I am only getting the last result.
I want to print out all the elements in the array.
For example: if num is 4546793 the output should be 454*67-9-3. I Did not count zero as an odd or even number.
function StringChallenge(num) {
let result = "";
for (let i = 0; i < num.length; i++) {
if (num[i] === 0) {
continue;
}
if (num[i - 1] % 2 == 0 && num[i] % 2 == 0) {
result = num[i - 1] + "*" + num[i];
continue;
}
if (num[i - 1] % 2 == !0 && num[i] % 2 == !0) {
result = num[i - 1] + "-" + num[i];
continue;
}
}
return result;
}
console.log(StringChallenge([4,5,4,6,7,9,3]));
You do not need to check as if&continue. Inserting given numbers to the result string and only adding "-" when index and previous are odd, and "*" when index and previous are even.
function StringChallenge(num) {
let result = "";
for (let i = 0; i < num.length; i++) {
if (num[i]%2 ===0) {// even
if(i !== 0 && num[i-1]%2===0){// previous is even either
result+="*"+num[i];
}else{
result+=num[i];
}
}else{// odd
if(i !== 0 && num[i-1]%2===1){// previous is odd either
result+="-"+num[i];
}else{
result+=num[i];
}
}
}
return result;
}
console.log(StringChallenge([4,5,4,6,7,9,3]));
Try this :)
function test(a){
let result=""
for(let i=0; i < a.length; i++){
if(a[i] != 0 && a[i-1] % 2 == 0 && a[i] % 2 == 0){
result = result + '*' + a[i]
}
else if (a[i] != 0 && a[i-1] % 2 != 0 && a[i] % 2 != 0){
result = result + '-' + a[i]
}
else{
result = result + a[i]
}
}
return result
}
console.log(test([4,5,4,6,7,9,3]));
As everyone has identified, the problem is you are not adding to result.
But here is a suggestion to make your code easier to read
// These one line functions make your code easier to read
function IsEven(num){
return num % 2 === 0;
}
function IsOdd(num){
return num % 2 !== 0;
}
function StringChallenge(numArray) {
// return empty string if not an array or empty array
if(!Array.isArray(numArray) || numArray.length === 0) return "";
let result = "" + numArray[0]; // use "" to coerce first element of numArray from number to string
for (let i = 1; i < numArray.length; i++) {
// focus on the conditions to determine the separator you want between each element
separator = "";
if (numArray[i] !== 0) {
if (IsEven(numArray[i]) && IsEven(numArray[i - 1])) {
separator = "*";
} else if (IsOdd(numArray[i]) && IsOdd(numArray[i - 1])){
separator = "-";
}
}
// build the result
result += separator + numArray[i];
}
return result;
}
I will do that this way :
== some advices for 2 cents ==
1 - try to make your code as readable as possible.
2 - use boolean tests rather than calculations to simply do a parity test
3 - ES7 has greatly improved the writing of JS code, so take advantage of it
console.log(StringChallenge([4,5,4,6,7,9,3])); // 454*67-9-3
function StringChallenge( Nums = [] )
{
const
isOdd = x => !!(x & 1) // Boolean test on binary value
, isEven = x => !(x & 1) && x!==0 // zero is not accepted as Even value
;
let result = `${Nums[0]??''}`; // get first number as
// result if Nums.length > 0
for (let i=1; i<Nums.length; i++)
{
if ( isOdd(Nums[i-1]) && isOdd(Nums[i]) ) result += '-';
if ( isEven(Nums[i-1]) && isEven(Nums[i]) ) result += '*';
result += `${Nums[i]}`; // same as Nums[i].toString(10);
}
return result
}
I hope this helps. I tried to keep it as simple as possible.
function StringChallenge(num) {
//start with a string to concatenate, or else interpreter tries to do math
operations
let result = num[0].toString();
function checkOdd(num){ //helper function to check if odd
return num % 2
}
for (let i = 0; i < num.length - 1; i++) {
if (checkOdd(num[i]) && checkOdd(num[i+1])) { //checks if both odd
result += `-${num[i+1]}`; //adds - and next number
} else if (!checkOdd(num[i]) && !checkOdd(num[i+1])) { //checks if both even
result += `*${num[i+1]}`; //adds * and next number
} else { //otherwise
result += num[i+1]; //just add next number
}
}
return result;
}
console.log(StringChallenge([4,5,4,6,7,9,3]));
Use +=. And, change your logic, your code prints out "4*67-99-3".
The zero check was pretty hard for me I hope the variables in my code explain itself. If not, let me know.
function even(num) {
return num % 2 === 0;
}
function odd(num) {
return num % 2 !== 0;
}
function StringChallenge(num) {
let result = "";
for (let i = 0; i < num.length; i++) {
var currentZero = num[i] === 0
var previousZero = num[i-1] === 0
var bothEven = even(num[i]) && even(num[i-1])
var bothOdd = odd(num[i]) && odd(num[i-1])
var firstNumber = (i === 0)
if (!currentZero) {
if (firstNumber) {
result += num[i]
} else {
if (bothEven && !previousZero) {
result += "*" + num[i]
} else if (bothOdd && !currentZero) {
result += "-" + num[i]
} else {
result += num[i]
}
}
}
}
return result;
}
console.log(StringChallenge([0,4,5,0,4,6,7,9,3]));

Caesar Cipher technique and reverse case in javascript

I am beginner and want to make my own function.
I want to hash the password by shifting every character by given x
positions and reverse to lowercase/uppercase.
I think the code below should return "EFGH7654" but it return 55 with no error message.
How can I fix it? Is it because of I put a function in a function?
Or I type wrong any thing?
function hashPassword(password, x) {
// password is a string, x is a number
// return a string
// (ex. password = 'ab1By', x = 3 so it should return "DE4eB")
function shift(text, s) {
result = "";
for (let i = 0; i < text.length; i++) {
let char = text[i];
if (char.toUpperCase(text[i])) {
let ch = String.fromCharCode((char.charCodeAt(0) + s - 65) % 26 + 65);
result += ch;
} else {
let ch = String.fromCharCode((char.charCodeAt(0) + s - 97) % 26 + 97);
result += ch;
}
}
return result;
}
function reversecase(x) {
var output = '';
for (var i = 0, len = x.length; i < len; i++) {
var character = x[i];
if (character == character.toLowerCase()) {
// The character is lowercase
output = output + character.toUpperCase();
} else {
// The character is uppercase
output = output + character.toLowerCase();
}
}
return output
}
var str = "";
var result = "";
var charcode = "";
for (var i = 0; i < password.length; i++) {
if (typeof password[i] === typeof str) {
char = shift(password[i], x)
charcode = reversecase(char)
result += charcode;
} else {
num = password[i] + x
number = num % 10
result += number.toString()
}
}
return result
};
console.log(hashPassword("abcd4321", 4))
There a quite some problems in your code.
The first problem here is not only the nesting, but the fact that you're defining the result variable in the outer function scope using the var keyword. Then you use (read/write) that variable in different places.
In function shift() (also in return statement)
In the outer function (also in return statement)
The thing you have to understand is, that you're referring to the same variable result every time. To ensure that your variables are scoped, i.e. are only valid within a block (if statement, function body, etc.), you should use the let or const keywords. This makes your code a lot safer.
The second problem are some assumptions you make regarding data types. If you have a string let s = "my string 123", the expression typeof s[x] === 'string' will be true for every x in s.
Another problem is the algorithm itself. The outer function hashPassword() iterates over all characters of the input string. Within that loop you call function shift(password[i], x), passing a single character. The first parameter of shift() is called text - and there is another for loop (which is confusing and does not make sense).
To make things short, please have a look at this simplified version:
function shift(char, x) {
let result;
const code = char.charCodeAt(0);
if (code >= 65 && code < 91) {
result = String.fromCharCode((code + x - 65) % 26 + 65);
}
else if (code >= 48 && code <= 57) {
result = String.fromCharCode((code + x - 48) % 10 + 48);
}
else {
result = String.fromCharCode((code + x - 97) % 26 + 97);
}
return result;
}
function reverseCase(character) {
if (character === character.toLowerCase()) {
return character.toUpperCase();
}
else {
return character.toLowerCase();
}
}
function hashPassword(password, x) {
let result = "";
for (let i = 0; i < password.length; i++) {
const char = shift(password[i], x);
result += reverseCase(char);
}
return result;
}
console.log(hashPassword("abcd4321", 4)); // Output: EFGH8765

How do you iterate over an array every x spots and replace with letter?

/Write a function called weave that accepts an input string and number. The function should return the string with every xth character replaced with an 'x'./
function weave(word,numSkip) {
let myString = word.split("");
numSkip -= 1;
for(let i = 0; i < myString.length; i++)
{
numSkip += numSkip;
myString[numSkip] = "x";
}
let newString = myString.join();
console.log(newString);
}
weave("weave",2);
I keep getting an infinite loop. I believe the answer I am looking for is "wxaxe".
Here's another solution, incrementing the for loop by the numToSkip parameter.
function weave(word, numToSkip) {
let letters = word.split("");
for (let i=numToSkip - 1; i < letters.length; i = i + numToSkip) {
letters[i] = "x"
}
return letters.join("");
}
Well you need to test each loop to check if it's a skip or not. Something as simple as the following will do:
function weave(word,numSkip) {
var arr = word.split("");
for(var i = 0; i < arr.length; i++)
{
if((i+1) % numSkip == 0) {
arr[i] = "x";
}
}
return arr.join("");
}
Here is a working example
Alternatively, you could use the map function:
function weave(word, numSkip) {
var arr = word.split("");
arr = arr.map(function(letter, index) {
return (index + 1) % numSkip ? letter : 'x';
});
return arr.join("");
}
Here is a working example
Here is a more re-usable function that allows specifying the character used for substitution:
function weave(input, skip, substitute) {
return input.split("").map(function(letter, index) {
return (index + 1) % skip ? letter : substitute;
}).join("");
}
Called like:
var result = weave('weave', 2, 'x');
Here is a working example
You dont need an array, string concatenation will do it, as well as the modulo operator:
function weave(str,x){
var result = "";
for(var i = 0; i < str.length; i++){
result += (i && (i+1)%x === 0)?"x":str[i];
}
return result;
}
With arrays:
const weave = (str,x) => str.split("").map((c,i)=>(i&&!((i+1)%x))?"x":c).join("");
You're getting your word greater in your loop every time, so your loop is infinite.
Try something like this :
for(let k = 1; k <= myString.length; k++)
{
if(k % numSkip == 0){
myString[k-1]='x';
}
}
Looking at what you have, I believe the reason you are getting an error is because the way you update numSkip, it eventually becomes larger than
myString.length. In my code snippet, I make i increment by numSkip which prevents the loop from ever executing when i is greater than myString.length. Please feel free to ask questions, and I will do my best to clarify!
JSFiddle of my solution (view the developer console to see the output.
function weave(word,numSkip) {
let myString = word.split("");
for(let i = numSkip - 1; i < myString.length; i += numSkip)
{
myString[i] = "x";
}
let newString = myString.join();
console.log(newString);
}
weave("weave",2);
Strings are immutable, you need a new string for the result and concat the actual character or the replacement.
function weave(word, numSkip) {
var i, result = '';
for (i = 0; i < word.length; i++) {
result += (i + 1) % numSkip ? word[i] : 'x';
}
return result;
}
console.log(weave("weave", 2));
console.log(weave("abcd efgh ijkl m", 5));
You can do this with fewer lines of code:
function weave(word, numSkip) {
word = word.split("");
for (i = 0; i < word.length; i++) {
word[i] = ((i + 1) % numSkip == 0) ? "x" : word[i];
}
return word.join("");
}
var result = weave("weave", 2);
console.log(result);

Insert dashes into a number

Any ideas on the following? I want to input a number into a function and insert dashes "-" between the odd digits. So 4567897 would become "456789-7". What I have so far is to convert the number into a string and then an array, then look for two odd numbers in a row and use the .splice() method to add the dashes where appropriate. It does not work and I figure I may not be on the right track anyway, and that there has to be a simpler solution.
function DashInsert(num) {
var numArr = num.toString().split('');
for (var i = 0; i < numArr.length; i++){
if (numArr[i]%2 != 0){
if (numArr[i+1]%2 != 0) {
numArr.splice(i, 0, "-");
}
}
}
return numArr;
}
The problem is you're changing the thing you're iterating over. If instead you maintain a separate output and input...
function insertDashes(num) {
var inStr = String(num);
var outStr = inStr[0], ii;
for (ii = 1; ii < inStr.length; ii++) {
if (inStr[ii-1] % 2 !== 0 && inStr[ii] % 2 !== 0) {
outStr += '-';
}
outStr += inStr[ii];
}
return outStr;
}
You can try using regular expressions
'4567897'.replace(/([13579])(?=[13579])/g, '$1-')
Regex Explained
So, we find an odd number (([13579]) is a capturing group meaning we can use it as a reference in the replacement $1) ensure that it is followed by another odd number in the non-capturing positive lookahead ((?=[13579])) and replace the matched odd number adding the - prefix
Here is the function to do it:
function dashes(number){
var numString = '';
var numArr = number.toString().split('');
console.log(numArr);
for(i = 0; i < numArr.length; i++){
if(numArr[i] % 2 === 1 && numArr[i+1] % 2 === 1){
numString += numArr[i] + '-';
}else{
numString += numArr[i];
}
}
console.log(numString);
}
dashes(456379);
Tested and everything.
Edit: OrangeDog's answer was posted earlier (by nearly a full half hour), I just wanted to make an answer which uses your code since you're almost there.
Using another array instead of splicing into one you were looping through (this happens to return a string using join):
var num = 4567897;
function DashInsert(num) {
var numArr = num.toString().split('');
var len = numArr.length;
var final = [];
for (var i = 0; i < len; i++){
final.push(numArr[i]);
if (numArr[i]%2 != 0){
if (i+1 < len && numArr[i+1]%2 != 0) {
final.push("-")
}
}
}
return final.join("");
}
alert(DashInsert(num));
function dashInsert(str) {
var arrayNumbers = str.split("");
var newString = "";
for (var i = 0; i < arrayNumbers.length; i++){
if(arrayNumbers[i] % 2 === 1 && arrayNumbers[i + 1] % 2 === 1){
newString = newString + arrayNumbers[i] + "-";
} else {
newString = newString + arrayNumbers[i];
}
}
return newString;
}
var result = dashInsert("3453246");
console.log(result);

Categories

Resources