I am running through some exercises and run into this on codewars. Its a simple exercise with Instructions to create a function called shortcut to remove all the lowercase vowels in a given string.
Examples:
shortcut("codewars") // --> cdwrs
shortcut("goodbye") // --> gdby
I am newbie so I thought up this solution. but it doesn't work and I have no idea why
function shortcut(string){
// create an array of individual characters
var stage1 = string.split('');
// loop through array and remove the unneeded characters
for (i = string.length-1; i >= 0; i--) {
if (stage1[i] === "a"||
stage1[i] === "e"||
stage1[i] === "i"||
stage1[i] === "o"||
stage1[i] === "u") {
stage1.splice(i,1)
;}
};
// turn the array back into a string
string = stage1.join('');
return shortcut;
}
My gut is telling me that it will probably something to like split and join not creating "true" array's and strings.
I did it at first with a regex to make it a little more reusable but that was a nightmare. I would be happy to take suggestions on other methods of acheiving the same thing.
You are returning the function itself, instead of returning string
Using regex:
var str = 'codewars';
var regex = /[aeiou]/g;
var result = str.replace(regex, '');
document.write(result);
if interested in Regular Expression ;)
function shortcut(str) {
return str.replace(/[aeiou]/g, "");
}
Related
I am trying to make the first letter of each word capitalized via toUpperCase method and the rest of the word is in the lower case via the toLowerCase method. But I am missing something... Why temp value is not matching with result[1][0] even if I am using that method for both?
Note: I know about other ways (map, replace, etc) for my solution, but I want to just use a for-loop with toUpperCase and toLowerCase methods.
function titleCase(str) {
let regex = /[^0-9\s]+/g;
var result = str.match(regex);
let temp = "";
for (let i = 0; i < result.length; i++) {
for (let j = 0; j < result[i].length; j++) {
result[1][0] = result[1][0].toUpperCase();
temp = result[1][0].toUpperCase();
}
}
console.log(temp); // Output is 'A'
console.log(result[1][0]); //Output is 'a'
// Normally 'temp' and 'result[1][0]' should be equal, but one returns a lowercase character and the other an uppercase character.
return str;
}
titleCase("I'm a little tea pot");
Your problem is not with the toUppercase(), it is with the reference.
When referencing result[1][0], why are you including the 0? You already have the second character with result[1]
result[1] === 'a'. No need to include the [0] as well.
Change your code so it looks like this:
function titleCase(str) {
let regex = /[^0-9\s]+/g;
var result = str.match(regex);
let temp = "";
result[1] = result[1].toUpperCase();
temp = result[1].toUpperCase();
console.log(temp); // Output is 'A'
console.log(result[1]); //Output is also 'A'
// both now equals capital A
return str;
}
titleCase("I'm a little tea pot");
EDIT:
Updating the function to uppercase the first letter of the word.
We can use ES6, which would make this really simple:
const capitalize = (string = '') => [...string].map((char, index) => index ? char : char.toUpperCase()).join('')
Use it: capitalize("hello") returns 'Hello'.
First we convert the string to an array, using the spread operator, to get each char individually as a string. Then we map each character to get the index to apply the uppercase to it. Index true means not equal 0, so (!index) is the first character. We then apply the uppercase function to it and then return the string.
If you want a more object oriented approach, we can do something like this:
String.prototype.capitalize = function(allWords) {
return (allWords) ?
this.split(' ').map(word => word.capitalize()).join(' ') :
return this.charAt(0).toUpperCase() + this.slice(1);
}
Use it: "hello, world!".capitalize(); returns "Hello, World"
We break down the phrase to words and then recursive calls until capitalising all words. If allWords is undefined, capitalise only the first word meaning the first character of the whole string.
I was tried to change a specific character in the string but strings are immutable in JS so this does not make sense.
I have a JavaScript object such as this:
{
a : {
b : c,
d : e
}
}
In my code, if b my was my starting point, I could input the string "this.$parent.d" which would evaluate to e.
However I could also input the string "this.$parent.b.$parent.d" to get the same result.
My question is if I am given a string such as "this.$parent.b.$parent.d" how can I simplify it to the first way?
I think what I need to do is use regex to replace all occurrences of "$parent.<anything>.$parent" with just "$parent" and that should work but not sure how to do this exactly.
In fact, you'll want to simplify an even shorter expression:
.prop.$parent
Such a substring should be removed, since it is a no-operation.
Here is how you could do that with a regular expression:
function simplify(str) {
const expression = /\.(?!\$parent\.)[\w$]+\.\$parent(?=\.|$)/g;
while (str.length > (str = str.replace(expression, "")).length) {}
return str;
}
var strings = [
"this.$parent.b.$parent.d", // should be this.$parent.d
"this.$parent.b.$parent.d.$parent.b.$parent.b", // should be this.$parent.b
"this.$parent.b.$parent.$parent.b.$parent", // should be this.$parent.$parent
"this.$parent.b.$parent.d.$parent.$parent.b", // should be this.$parent.$parent.b
"this.$parent.b.c.$parent.$parent.b", // should be this.$parent.b
"this.$parentX.b.$parentX", // should be this.$parentX.b.$parentX
];
const results = strings.map(simplify);
console.log(results);
I think the regex you're looking for is this:
/\.\$parent\.[^$]?[^p]?[^a]?[^r]?[^e]?[^n]?[^t]?\.\$parent/g
Someone who is better at regex than me can hopefully simplify this, since it seems very verbose.
The solution below uses a recursive function, because if there are two instances that get replaced in the same string, you have now created another instance of .$parent.*.$parent, which needs to then get replaced with just .$parent.
For example:
this.$parent.b.$parent.d.$parent.$parent.b
After 1 .replace() --> this.$parent.d.$parent.$parent.b
After 2 .replace() --> this.$parent.$parent.b
Here's the code in action:
var expression = /\.\$parent\.[^$]?[^p]?[^a]?[^r]?[^e]?[^n]?[^t]?\.\$parent/g;
var strings = [
"this.$parent.b.$parent.d", // should be this.$parent.d
"this.$parent.b.$parent.d.$parent.b.$parent.b", // should be this.$parent.b
"this.$parent.b.$parent.$parent.b.$parent", // should be this.$parent.$parent
"this.$parent.b.$parent.d.$parent.$parent.b" // should be this.$parent.$parent.b
];
function simplify (str) {
var str = str.replace(expression, ".$parent");
if (expression.test(str)) {
return simplify(str);
}
return str;
}
strings.forEach(function (str) {
console.log(simplify(str));
});
I wrote this bit of code a a part of an exercise to check weather or not a string is palindromes. They program is working correctly in terms of checking the string but it does not return false when the string is not palindromes. What am I doing wrong? thanks
//convert the string to array
var stringArr = [ ];
var bool;
function palindrome(str) {
// make lowercase
var lowerCase = str.toLowerCase();
//remove numbers, special characters, and white spaces
var noNumbers = lowerCase.replace(/[0-9]/g, '');
var noSpecials = noNumbers.replace(/\W+/g, " ");
var finalString = noSpecials.replace(/\s/g, '');
stringArr = finalString.split("");
if (stringArr.sort(frontToBack)==stringArr.sort(backToFront)) {
bool = true;
}
else {
bool= false;
}
return bool;
}
function frontToBack (a,b) {return a-b;}
function backToFront (a,b) {return b-a;}
palindrome("eye");
if (stringArr.sort(frontToBack)==stringArr.sort(backToFront)) { is your problem.
In JavaScript, the sort method updates the value of the variable you are sorting. So in your comparison, once both sort's have run, both end up with the same value (since the second sort, effectively overrides the first).
For example.
var a = [1,7,3];
a.sort();
console.log(a); // will print 1,3,7
Edit: had a quick test, I think eavidan's suggestion is probably the best one.
Edit2: Just put together a quick version of a hopefully working palindrome function :)
function palindrome(str) { return str.split("").reverse().join("") == str;}
It is because string subtraction yields NaN, which means both sorted arrays are the same as the original.
Even if you did convert to ASCII coding, you sort the entire string, then for instance the string abba would be sorted front to back as aabb and back to front as bbaa. (edit: and also what Carl wrote about sort changing the original array. Still - sort is not the way to go here)
What you should do is just reverse the string (using reverse on the array) and compare.
You might do as follows;
var isPalindrome = s => { var t = s.toLowerCase()
.replace(/\s+/g,"");
return [].slice.call(t)
.reverse()
.every((b,i) => b === t[i]);
};
console.log(isPalindrome("Was it a car or a cat I saw"));
console.log(isPalindrome("This is not a palindrome"));
function pal()
{
var x=document.getElementById("a").value;
//input String
var y="";
//blank String
for (i=x.length-1;i>=0;i--)
//string run from backward
{
y=y+x[i];
//store string last to first one by one in blank string
}
if(x==y)
//compare blank and original string equal or not
{
console.log("Palindrome");
}
else
{
console.log("Not Palindrome ");
}
}
I am trying to write a palindrome code, so I am using the split and reverse methods. Is my below logic correct? Can I directly use the reverse method instead of giving split and then reverse?
If I give == it prints palindrome where as if I give === it prints not palindrome. I am a beginner in JS and I am trying to learn.
var actualWord = "madam"
var splittedWord = actualWord.split();
console.log("splittedWord---->" + splittedWord);
var reversedWord = splittedWord.reverse();
console.log("reversedWord---->" + reversedWord);
console.log("boolean" + reversedWord === actualWord);
if (reversedWord === actualWord) {
console.log("palindrome");
} else {
console.log("not palindrome")
}
Your logic is flawed as split() with no parameter to split by returns the original word, which then means that reverse() has no effect as you're working on a single element array. You are also attempting to check arrays for equality, which will not work.
To do what you require you need to split by '' to generate a character array which you can then reverse() and join() back together to invert the characters of the word. Then you can compare the words to discover if the original was a palindrome. Try this:
var actualWord = "madam"
var reverseWord = actualWord.split('').reverse().join('');
console.log(actualWord, reverseWord);
if (actualWord === reverseWord) {
console.log(actualWord + " IS a palindrome");
} else {
console.log(actualWord + " IS NOT a palindrome")
}
Working example
Taking this a step further you could extract the logic to it's own function and make the string comparison case-insensitive:
console.log('madam', isPalindrome('madam'));
console.log('madame', isPalindrome('madame'));
console.log('raceCAR', isPalindrome('raceCAR'));
function isPalindrome(word) {
var reverseWord = word.split('').reverse().join('');
return word.toLowerCase() === reverseWord.toLowerCase();
}
Example fiddle
Several things needed to make your code correct:
Split the words using .split("") not .split()
Create strings from the arrays using .join("")
Put parentheses around the comparator in your "boolean" line, otherwise the "+" will be performed before the "==="
var actualWord = "madam";
var splittedWord = actualWord.split("");
log("splittedWord---->" + splittedWord.join(""));
var reversedWord = splittedWord.reverse();
log("reversedWord---->" + reversedWord.join(""));
log("boolean---->" + (reversedWord.join("") === actualWord));
if (reversedWord.join("") === actualWord) {
log("palindrome");
} else {
log("not palindrome")
}
function log(str) {
document.body.appendChild(document.createElement("p")).innerHTML = str;
}
The == operator will compare for equality after doing any necessary
type conversions. The === operator will not do the conversion, so if
two values are not the same type === will simply return false. It's
this case where === will be faster, and may return a different result
than ==. In all other cases performance will be the same.
e.g.-
"1" == 1
true
"1" === 1
false
in your case, reversedWord is an array but actualWord is string, hence you get false when using ===, but when you use == JS does the necessary type conversion for you and you get true.
You have to call the split function before the reverse function because you are referring to a string and not an array.
I understand the .split() function quite well. But what I can seem to figure out is how to split in certain places but not in others. Sounds confusing? Well I mean for example, lets say I use .split(",") on the following string:
div:(li,div),div
Is it possible to split it so that only the commas ouside of the parentheses get split.
So the string above with the split method should return:
['div:(li,div)', 'div']
Of course at the moment it is also splitting the first comma inside of the parentheses, returning:
['div:(li', 'div)', 'div']
Is there some way to make this work like I desire?
If your expected strings are not going to become more complicated than this, you don't have to worry about writing code to parse them. Regex will work just fine.
http://jsfiddle.net/dC5HN/1/
var str = "div:(li,div),div:(li,div),div";
var parts = str.split(/,(?=(?:[^\)]|\([^\)]*\))*$)/g);
console.log(parts);
outputs:
["div:(li,div)", "div:(li,div)", "div"]
REGEX is not built for this sort of thing, which is essentially parsing.
When faced with this sort of situation previously I've first temporarily replaced the parenthesised parts with a placeholder, then split, then replaced the placeholders with the original parenthised parts.
A bit hacky, but it works:
var str = 'div:(li,div),div',
repls = [];
//first strip out parenthesised parts and store in array
str = str.replace(/\([^\)]*\)/g, function($0) {
repls.push($0);
return '*repl'+(repls.length - 1)+'*';
});
//with the parenthisised parts removed, split the string then iteratively
//reinstate the removed parenthisised parts
var pieces = str.split(',').map(function(val, index) {
return val.replace(/\*repl(\d+)\*/, function($0, $1) {
return repls[$1];
});
});
//test
console.log(pieces); //["div:(li,div)","div"]
This function will split whatever you specify in splitChar, but ignore that value if inside parenthesis:
function customSplit(stringToSplit, splitChar){
var arr = new Array();
var isParenOpen = 0
var curChar;
var curString = "";
for (var i = 0; i < stringToSplit.length; i++) {
curChar = stringToSplit.substr(i, 1);
switch(curChar) {
case "(":
isParenOpen++;
break;
case ")":
if(isParenOpen > 0) isParenOpen--;
break;
case splitChar:
if (isParenOpen < 1) {
arr.push(curString);
curString = "";
continue;
}
}
curString += curChar;
}
if (curString.length > 0) {
arr.push(curString);
}
return arr;
}