Parsing out all Special Characters - javascript

I'll preface my question by saying I know using strictly regex for this is a lot easier/cleaner of a solution and I plan on refactoring my code to do just that.
That said, I wanted to see if my brute force way could actually work.
Basically, this is a simple letter substitution cipher that replaces a letter with the letter 13 letters after it in the alphabet.
If the letter is a special character, it keeps that special character.
I have my function returning the correct letters and have some regex code in there to check for special characters but it keeps saying it is finding 13 occurrences of a special character and I can't seem to figure out why. Any thoughts?
function rot13(message) {
let alpha = "abcdefghijklmnopqrstuvwxyz"
let capAlpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
let special = /[ !##$%^&*()_+\-=\[\]{};':"\\|,.<>\/?\s]/g;
let arrAlpha = alpha.split("")
let messageSplit = message.split("")
let sum = 0
let newSum = 0
let answer = []
for (let i = 0; i < message.length; i++) {
for (let j = 0; j < alpha.length; j++) {
if (message[i] === alpha[j]) {
if (j <= 12) {
answer.push(alpha[j + 13])
} else {
sum = 25 - j
newSum = 12 - sum
answer.push(alpha[newSum]);
sum = 0
}
} else if (message[i] === capAlpha[j]) {
if (j <= 12) {
answer.push(capAlpha[j + 13])
} else {
sum = 25 - j
newSum = 12 - sum
answer.push(capAlpha[newSum]);
sum = 0
}
} else if (special.test(message[i])) {
console.log("hello");
answer.push(message[i])
}
}
}
return (answer.join(""));
}
console.log(rot13("Hello"));
console.log("---------------");
rot13("Hello World!");

The problem appears to be in this snippet:
else if (special.test(message[i])) {
console.log("hello");
answer.push(message[i])
}
Because you're looping over the length of alpha, it's executing that check 13 times, and thus pushing the space into answer 13 times. If you add break; after the push, it'll exit the j loop and proceed to the next iteration of the i loop.

Related

I have a for counting occurrences of a letter but can only count from 1 to 9

I have two inputs (original and comprimida). The original one is like this one "bbbddef" which in a compressed form would be "b3d2e1f1" (Three times b, two times d, one for e and one for f). However, when I have a original like this one: "aaaaaaaaaaabcdda" that should be "a11b1c1d2a1" it only counts till 9 because the for cannot go above 9 (two digits). How can I solve this? Thanks in advance.
Here's the code
var original = "aaaaaaaaaaabcdda";
var comprimida = "a11b1c1d2a1";
var res = "";
for(var i = 0; i < comprimida.length; i+=2){
let letra = comprimida.charAt(i);
let numero = comprimida.charAt(i+1);
for(let j=0; j<numero; j++){
res += letra;
}
}
if(original == res){
alert("SI");
} else {
alert("NO");
}
The code should do 'a' 11 times and it's not doing so since it only takes the first 1 from 11. But I can't make it count two digits only because then every other solution for 'a' being less than 10 would be wrong.
This solution reads char by char. If it's a letter it is being remembered, if it's a digit it's being calculated to be a number. Then, if it's a letter again we repeat number of times the last remembered letter.
var comprimida = "a11b1c1d2a1";
var result = "";
var current = "";
var number = 0;
comprimida.split("").forEach(function(char) {
if (char >= 'a' && char <= 'z') {
result += current.repeat(number)
number = 0;
current = char;
} else {
number = number * 10 + +char
}
})
result += current.repeat(number)
console.log(result)

Multiplicative Persistence Codewars Challenge

I've been working on a kata from Codewars, the challenge is to write a function, persistence, that takes in a positive parameter num and returns its multiplicative persistence, which is the number of times you must multiply the digits in num until you reach a single digit.
Example:
persistence(39) === 3 // because 3*9 = 27, 2*7 = 14, 1*4=4
// and 4 has only one digit
persistence(999) === 4 // because 9*9*9 = 729, 7*2*9 = 126,
// 1*2*6 = 12, and finally 1*2 = 2
persistence(4) === 0 // because 4 is already a one-digit number
While trying to figure this out I came across a solution online (shown below) and after trying to understand its logic, I couldn't see why the code didn't work
var count = 0;
function persistence(num) {
if (num.toString().length === 1) {
return count;
}
count++;
var mult = 1;
var splitStr = num.toString().split("");
for (var i = 0; i <= splitStr; i++) {
mult *= parseFloat(splitStr[i])
}
return persistence(parseFloat(mult));
}
The output for any single digit number will be 0 which is correct however for any number that is multiple digits, the persistence always logs as 1 and I can't seem to figure out why, any help would be greatly appreciated.
The posted code has quite a few problems.
for (var i = 0; i <= splitStr; i++) {
But splitStr is an array, not a number; i <= splitStr doesn't make sense. It should check against splitStr.length instead of splitStr.
Another problem is that it should use i <, not i <=, else the final splitStr[i] will be undefined.
Another problem is that the count variable is global, so more than one call of persistence will result in inaccurate results. There's no need for a count variable at all. To fix it:
function persistence(num) {
if (num.toString().length === 1) {
return 0;
}
var mult = 1;
var splitStr = num.toString().split("");
for (var i = 0; i < splitStr.length; i++) {
mult *= parseFloat(splitStr[i])
}
return 1 + persistence(parseFloat(mult));
}
console.log(
persistence(999),
persistence(39),
persistence(4)
);
Or, one could avoid the for loop entirely, and use more appropriate array methods:
function persistence(num) {
const str = num.toString();
if (str.length === 1) {
return 0;
}
const nextNum = str.split('').reduce((a, b) => a * b, 1);
return 1 + persistence(nextNum);
}
console.log(
persistence(999),
persistence(39),
persistence(4)
);
or we can use while loop with reduce array method
const persistence=(num)=>{
let splitNumArr=num.toString().split('')
let newList
let count=0
while(splitNumArr.length>1){
newList=splitNumArr.reduce((acc,curr)=>{
return acc*=curr
})
splitNumArr=newList.toString().split('')
count++
}
return count
}
console.log(persistence(39))===3
console.log(persistence(999))===4
console.log(persistence(9))===0

Whats wrong with my palindrome? (javascript)

I have written this js code for palindrome, I know there are better and more efficient palindrome methods online but I want to know why I am unable to get my palindrome function to work properly?
CODE:
var pal = function(str) {
var len = str.length;
for (var i = 0; i < len; i++) {
var comp1 = str.substring(i, i + 1);
for (var j = len; j > 0; j--) {
var comp2 = str.substring(j - 1, j);
}
if (comp1 != comp2) {
console.log("not palindrome")
break;
} else {
console.log('palindrome')
}
}
}
pal('maddog');
OUTPUT :
palindrome
not palindrome
There are lot of better algorithms to check Palindrome. Let use the similar algorithm that you are using.
We basically use two pointers - left and right, and move to middle at the same time. In the original question, left pointer and right pointer doesn't move at the same time.
Pointers should move like this -
a b c b a
^ ^
a b c b a
^ ^
a b c b a
^
var isPalindrome = function (str) {
for (var i = 0, j = str.length-1; i < j; i++ , j--) {
if (str[i] != str[j]) {
return false;
}
}
return true;
}
console.log('maddog : ' + isPalindrome('maddog'));
console.log('abcba : ' + isPalindrome('abcba'));
console.log('deed : ' + isPalindrome('deed'));
console.log('a : ' + isPalindrome('a'));
Try the following code. It works by dividing the string length by 2, and then iterating up, checking mirroring characters against each other:
var pal = function(str){
var len = str.length;
for(var i = 0; i < Math.floor(len/2); i++){
if(str[i] != str[(len-1)-i]){
return false;
}
}
return true;
}
console.log(pal("bunny"));
console.log(pal("amoreroma"));
The inner loop is totally unnecessary. It does the same thing every time -- it loops through the whole string, starting from the end, repeatedly setting comp2 to the character; when it's done, comp2 always contains the first character. So your function just tests whether every character in the string is the same as the first character.
To test if something is a palindrome, you need to compare each character with the corresponding character from the other end of the string. You don't need two loops for this. You also only need to loop through the first half of the string, not the whole string.
Finally, you should only echo Palindrome at the end of the loop. Inside the loop you only know that one character matches, not all of them.
var pal = function(str) {
var len = str.length;
var half = Math.floor(len / 2);
var isPal = true;
for (var i = 0; i < half; i++) {
var comp1 = str[i];
var comp2 = str[len - i - 1];
if (comp1 != comp2) {
console.log("not palindrome")
isPal = false;
break;
}
}
if (isPal) {
console.log('palindrome')
}
}
pal('maddog');
pal('maddam');
You don't really need the nested loops, you can just loop backwards through the string to invert the string and then compare it to the original string. I updated the Snippet to work.
Before, your code was not inverting the string but rather just iterating through the characters and assigning them to the comp1 and comp1 variables. You need to concatenate the strings in order to build the new string backwards comp = comp + str.substring(j-1, j);
var pal = function(str) {
var len = str.length;
var comp = '';
for (var j = len; j > 0; j--) {
comp = comp + str.substring(j - 1, j);
}
if (str !== comp) {
console.log("not palindrome")
return;
}
console.log('palindrome')
}
pal('arepera');

Return the first word with the greatest number of repeated letters

This is a question from coderbyte’s easy set. Many people asked about it already, but I’m really curious about what’s wrong with my particular solution (I know it’s a pretty dumb and inefficient one..)
Original question:
Have the function LetterCountI(str) take the str parameter being passed and return the first word with the greatest number of repeated letters. For example: "Today, is the greatest day ever!" should return greatest because it has 2 e's (and 2 t's) and it comes before ever which also has 2 e's. If there are no words with repeating letters return -1. Words will be separated by spaces.
My solution works most of the time. But if it seems the last word of the input isn’t valued by my code. For example, for “a bb ccc”, “bb” will be returned instead of “ccc”. But the funny thing here is if the string only contains one word, the result is correct. For example, “ccc” returns “ccc”.
Please tell me where I was wrong. Thank you in advance!
function LetterCountI(str) {
str.toLowerCase();
var arr = str.split(" ");
var count = 0;
var word = "-1";
for (var i = 0; i < arr.length; i++) {
for (var a = 0; a < arr[i].length; a++) {
var countNew = 0;
for (var b = a + 1; b < arr[i].length; b++) {
if(arr[i][a] === arr[i][b])
countNew += 1;
}
if (countNew > count) {
count = countNew;
word = arr[i];
}
}
return word;
}
}
Please find below the workable version of your code:
function LetterCountI(str) {
str = str.toLowerCase();
var arr = str.split(" ");
var count = 0;
var word = "-1";
for (var i = 0; i < arr.length; i++) {
for (var a = 0; a < arr[i].length; a++) {
var countNew = 0;
for (var b = a + 1; b < arr[i].length; b++) {
if (arr[i][a] === arr[i][b])
countNew += 1;
}
if (countNew > count) {
count = countNew;
word = arr[i];
}
}
}
return word;
}
Here is the Java code soln for your problem.
You have returned your answer incorrectly. You should have returned word/Answer/res out of "for loops".
Check my chode here.
public static String StringChallenge( String str) {
String[] arr = str.split(" ");
int count = 0; String res = "-1";
for (int i = 0; i < arr.length ; i++) {
for (int j = 0; j < arr[i].length() ; j++) {
int counter = 0;
for (int k = j + 1; k < arr[i].length() ; k++) {
if(arr[i].charAt(j) === arr[i].charAt(k) )
counter ++;
}
if (counter > count) {
count = counter; res = arr[i];
}
}
return res;
}
}
I think the problem is that you're placing the return statement inside your outermost loop. It should be inside your inner loop.
So you have to place the return statement within the inner loop.
Correct use of return
if (countNew > count) {
count = countNew;
word = arr[i];
}
return word;
}
}
}
You need to move the return word; statement outside of the loop to fix your version.
I also put together another take on the algorithm that relies on a few built in javascript methods like Array.map and Math.max, just for reference. I ran a few tests and it seems to be a few milliseconds faster, but not by much.
function LetterCountI(str) {
var maxCount = 0;
var word = '-1';
//split string into words based on spaces and count repeated characters
str.toLowerCase().split(" ").forEach(function(currentWord){
var hash = {};
//split word into characters and increment a hash map for repeated values
currentWord.split('').forEach(function(letter){
if (hash.hasOwnProperty(letter)) {
hash[letter]++;
} else {
hash[letter] = 1;
}
});
//covert the hash map to an array of character counts
var characterCounts = Object.keys(hash).map(function(key){ return hash[key]; });
//find the maximum value in the squashed array
var currentMaxRepeatedCount = Math.max.apply(null, characterCounts);
//if the current word has a higher repeat count than previous max, replace it
if (currentMaxRepeatedCount > maxCount) {
maxCount = currentMaxRepeatedCount;
word = currentWord;
}
});
return word;
}
Yet another solution in a more functional programming style:
JavaScript
function LetterCountI(str) {
return ((str = str.split(' ').map(function(word) {
var letters = word.split('').reduce(function(map, letter) {
map[letter] = map.hasOwnProperty(letter) ? map[letter] + 1 : 1;
return map;
}, {}); // map of letters to number of occurrences in the word
return {
word: word,
count: Object.keys(letters).filter(function(letter) {
return letters[letter] > 1;
}).length // number of repeated letters
};
}).sort(function(a, b) { // Sort words by number of repeated letters
return b.count - a.count;
}).shift()) && str.count && str.word) || -1; // return first word with maximum repeated letters or -1
}
console.log(LetterCountI('Today, is the greatest day ever!')); // => greatest
Plunker
http://plnkr.co/edit/BRywasUkQ3KYdhRpBfU2?p=preview
I recommend use regular expression: /a+/g to find a list of letter with a key word a.
My example :
var str = aa yyyyy bb cccc cc dd bbb;
Fist, find a list of different word :
>>> ["a", "y", "b", "c", "d"]
Use regular expression for each word in list of different word :
var word = lstDiffWord[1];
var
wordcount = str.match(new RegExp(word+'+','g'));
console.log(wordcount);
>>>>["yyyyy"]
Here is full example: http://jsfiddle.net/sxro0sLq/4/

How can I shortened this?

I am trying to self teach myself programming and started with javascript. To learn more I have been completing challenges to practice and one challenge was to write a script that would determine the first case of the word in a string with the most repeated letters. I was able to complete it with this code I made:
string = "Hey i believe";
string = string.split(" ");
stringarray = [];
longestlength = 0;
for (i = 0; i < string.length; i++) {
stringarray.push(0);
}
for (i = 0; i < string.length; i++) {
if (string[i].length > longestlength) {
longestlength = string[i].length;
longestword = string[i];
}
}
for (x = 0; x < string.length; x++) {
y = 0;
z = 0;
while (z < string[x].length) {
if (string[x].substr(z,1) == string[x].substr(y,1) && z !== y) {
stringarray[x] += 1;
y = string[x].length -1;
}
y++;
if (y == string[x].length) {
z++;
y = z;
}
}
}
if (Math.max.apply(null,stringarray) === 0) {
mostrptltword = -1;
}
else {
mostrptltword = string[stringarray.indexOf(Math.max.apply(null,stringarray))];
}
console.log(mostrptltword);
But to get all the points possible for the challenge it must be completed in less than 10 minutes this took me 25 mins. So my question is am I over complicating things; causing me to write a much longer script than needed? I have read a little bit about things like Regular Expressions and how they can really shortened script lengths and the time it takes to write them would that or maybe another technique of been more useful than all the loops I had to make?
var words = "Heyyyyy I believe".split(' '); // split the words into an array
var values = [], // total of times that a letter appears
k = 0, // 'global' counter. I'm using this to iterate over the values array
heigher = 0, // holds de heigher occurrence of a letter
letter = ""; // the letter that most appears in that word
word = ""; // the word
// iterate over all the words
for(var i = 0; i < words.length; i++) {
// iterate over each letter in each word
for(var j = 0; j < words[i].length; j++) {
// holds the occurrence time
// RegEx: get the word in the position 'i' and check how many times the letter appears on the position [j] appears
values[k] = words[i].match(new RegExp(words[i][j],'g')).length;
// check if the next letter appears more times than the previous one
if(values[k] > heigher) {
// hold the values of interest
heigher = values[k];
letter = words[i][j];
word = words[i];
}
k++;
}
}
console.log("word: " + word + " letter: " + letter + " total: " + heigher);
jsfiddle: http://jsfiddle.net/felipemiosso/FyCHG/
The is commented. Hope it helps :)

Categories

Resources