I'm taking freecodecamp challenge "Check for Palindromes". Write a function to check if a given string is palindrome. Here is my code:
function palindrome(str) {
str = str.toLowerCase();
for(var i=0; i<str.length; i++){
if((str[i] > 'z' || str[i] < 'a') && (str[i] < '0' || str[i] > '9')){
str = str.replace(str[i], '');
}
}
for(i=0; i<str.length/2; i++){
if(str[i] != str[str.length-1-i]){
return false;
}
}
return true;
}
But it not worked properly. When I use replace(/[\W_]/g, ''); :
function palindrome(str) {
str = str.toLowerCase().replace(/[\W_]/g, '');
// for(var i=0; i<str.length; i++){
// if((str[i] > 'z' || str[i] < 'a') && (str[i] < '0' || str[i] > '9')){
// str = str.replace(str[i], '');
// }
// }
for(i=0; i<str.length/2; i++){
if(str[i] != str[str.length-1-i]){
return false;
}
}
return true;
}
The function worked properly. Is my first method not correct?
Palindromes ignore capitalization, spaces, punctuation and newlines and so on.
So:
A man. A plan. A canal: Panama!
Is a valid palindrome.
As such, you need to strip all punctuation and whitespace out of your string before trying to evaluate it, such that the string you're actually evaluating is:
amanaplanacanalpanama
Then it's easy to do whatever comparator you'd like on the remaining characters.
I did one of these a while ago and included some tests, it might be worth looking at: https://github.com/pvencill/palindrome
Related
Am I somewhere near the solution? I always get a double number of the consonants.
I was convinced that this was the correct approach.
function consonants(str) {
var countConsonants = 0;
for (var i = 0; i <= str.length; i++) {
if (str[i] !== "a" || str[i] !== "e" || str[i] !== "i" ||
str[i] !== "o" || str[i] !== "u" || str[i] !== " ") {
countConsonants += 1;
}
}
return (countConsonants);
}
consonants("asdfghaaa");
I am expecting an answer of 5 i.e. sdfgh are the consonants.
Your logic is flawed, The operator in your condition should be AND && not OR ||, since you want to compare all the chars not just one of them :
function consonants(str) {
var countConsonants = 0;
for (var i = 0; i < str.length; i++) {
if (str[i] !== "a" && str[i] !== "e" && str[i] !== "i" &&
str[i] !== "o" && str[i] !== "u" && str[i] !== " ") {
countConsonants++;
}
}
return (countConsonants);
}
console.log(consonants("asdfghaaa"));
NOTE : The loop should stop at length-1 since arrays are 0 based, so replace :
for (var i = 0; i <= str.length; i++) {
__________________^^
By :
for (var i = 0; i < str.length; i++) {
__________________^
Hope this helps.
You can do
let str = 'asdfghaaa';
let result = str.split('').filter(e => e.match(/[^aeiou]/) != null).length;
console.log(result);
The main problem in counts lies within your conditions.
You're increasing the number of consonants whenever one of the conditions fail (that's what || does, known as the OR operator). So whenever a character !== "a" OR !== "e", you're increasing the count, which is wrong. (Imagine that a is !== 'e', so you're counting a as a consonant).
Change the || binary operator to && (AND); this way, you're only increasing the consonant count whenever the current character str[i] is not among the values you're verifying for (a, e, i, o, u, ' ').
As others pointed out, you're also likely to run into an error as the max value of i should be Length-1.
There also other problems you need to consider:
What happens when the character is an uppercase letter?
What happens when the character is a punctuation mark or a number?
For a beginner, this may not be relevant, but it's well worth getting these techniques under your skin: It's more readable to create an array that contains all of the value you're verifying for ["a","e", etc] and then, for each char in the source string, just verify if array.indexOf(str[i]) >= 0 (which means that the character is included in the array).
Your answer is almost right. The only problem is || instead of &&. You're checking that it's not a AND it's not e AND it's not i, etc. Your function comes out true for every letter, since a is (not a || not e), right?
function consonants (str) {
return str.match(/[aeoiu]/gi)||[].length;
}
May be not good for long string.
You need to and your conditions because if you use || the condition always evaluates to true. Your loop should go from 0 to index < str.length.
function consonants(str) {
var countConsonants = 0;
for (var i = 0; i < str.length; i++) {
if (str.charAt(i) !== "a" && str.charAt(i) !== "e" && str.charAt(i) !== "i"
&& str.charAt(i) !== "o" && str.charAt(i) !== "u" && str.charAt(i) !== " ") {
countConsonants++;
}
}
return countConsonants;
}
console.log(consonants("asdfghaaa"));
I had this challenge too here is how i did:
const paragraph = "A quick brow fox is trying to bite me."
paragraph.match(/(?![aeiou])[a-z]/gi, "").length
Source: https://forum.freecodecamp.org/t/regex-for-consonants/282833/4
Here is a working example
let str="Hello world.";
let vowel=str.match(/[aeiou]/gi).length;
let consonant = str.match(/[^aeiou .]/gi).length;
console.log("Vowel "+vowel+"\n");
console.log("Vowel "+consonant+"\n");
For example if I had the string "GCG", I'd like to insert a
"C" at every "G" match, and a "G" at every "C" match, making it GCCGGC.
So far I have the following, but it prints GCGCGC.
function pairElement(str) {
for(i = 0; i < str.length; i++) {
if(str[i] == "G") {
return str.replace(/([GC+/])/g, "GC");
} else if (str[i] == "C") {
return str.replace(/([?=CG+/])/g, "CG");
}
}
}
pairElement("GCG");
Edit: I think only the first if statement is executing and not running the else if. Are there any other methods I can use to search for different letters, not only one, and insert another letter depending on what the search for letter is?
You can convert the string into array using splitand then iterate through the array and replace each character.
Then you can use join to convert the array into string.
var string = 'GCG';
var str = string.split('').map(c => {
if(c === 'G') c = 'GC';
else if (c === 'C') c = 'CG';
return c;
}).join('');
console.log('String ' + string);
console.log('New String ' + str);
you can do
function pairElement(str) {
return str.replace(/G|C/g, e => e=='G'?'GC':'CG')
}
console.log(pairElement("GCG"));
You are not using recursion. Once it hits the return statement, the control exits. A better way would be to use regex as one of the answers suggested but if you want to just make tiny modifications in your own code, maybe try something like this.
function pairElement(str) {
var newStr= ""; // using new string to make it more readible
for(i = 0; i < str.length; i++) {
if(str[i] == "G") {
newStr = newStr + str[i] + "C";
} else if (str[i] == "C") {
newStr = newStr + str[i] + "G";
} else {
newStr = newStr + str[i]; //you didn't specify what do you want to do in this case
}
}
return newStr;
}
pairElement("GCG");
input
books.copies.[read_by.[p_id="65784"].page=5468].text.[paragraph="20"].letters
the idea is to split the string by dots but ignore those inside square brackets
so after splitting there should be an array
[
'books',
'copies',
'[read_by.[p_id="65784"].page=5468]',
'text',
'[paragraph="20"]',
'letters'
]
I already looked at this answer but it doesn't work with nested square brackets, which is what i need. Also I'm using javascript, so negative lookbehinds are not supported.
Help is much appreciated.
Edit 1: expand example
It isn't possible to do it with a regex in Javascript that isn't able to match nested structures. You need to use the good old method: a stack.
var text = 'books.copies.[read_by.[p_id="65784"].page=5468].text.[paragraph="20"].letters';
var item = '', result = [], stack = 0;
for (var i=0; i < text.length; i++) {
if ( text[i] == '.' && stack == 0 ) {
result.push(item);
item = '';
continue;
} else if ( text[i] == '[' ) {
stack++;
} else if ( text[i] == ']' ) {
stack--;
}
item += text[i];
}
result.push(item);
console.log(result);
You need to write a parser for this since a JavaScript regex does not support regex recursion, nor balanced constructs.
The point in these functions is that they keep a stack (level, openBrackets) of opening delimiters (in your case, it is [) and then check the stack state: if the stack is not emppty, the found . is considered inside the brackets, and is thus just appended to the current match. Else, when the stack is empty, the . found is considered outside of brackets, and is thus used to split on (the current value is appended to the output array (result, ret)).
function splitByDotsOutsideBrackets(string){
var openBrackets = 0, ret = [], i = 0;
while (i < string.length){
if (string.charAt(i) == '[')
openBrackets++;
else if (string.charAt(i) == ']')
openBrackets--;
else if (string.charAt(i) == "." && openBrackets == 0){
ret.push(string.substr(0, i));
string = string.substr(i + 1);
i = -1;
}
i++;
}
if (string != "") ret.push(string);
return ret;
}
var res = splitByDotsOutsideBrackets('books.copies.[read_by.[p_id="65784"].page=5468].text.[paragraph="20"].letters');
console.log(res);
Or another variation:
function splitOnDotsOutsideNestedBrackets(str) {
var result = [], start = 0, level = 0;
for (var i = 0; i < str.length; ++i) {
switch (str[i]) {
case '[':
++level;
break;
case ']':
if (level > 0)
--level;
break;
case '.':
if (level)
break;
if (start < i)
result.push(str.substr(start, i - start));
start = i + 1;
break;
}
}
if (start < i)
result.push(str.substr(start, i - start));
return result;
}
var s = 'books.copies.[read_by.[p_id="65784"].page=5468].text.[paragraph="20"].letters';
console.log(splitOnDotsOutsideNestedBrackets(s))
Adapted from one of my previous answers.
I have written the logic to check for parenthesis for "(" and ")" but there seems to an issue when parenthesis gets mixed. This is because I'm just comparing the total parenthesis count.
This is what i wrote
function checkParanthesis(str){
var depth=0;
for(var i in str){
if(str[i] == "(" || str[i] == "{" || str[i] == "[")
depth++;
else if(str[i] == ")" || str[i] == "}" || str[i] == "]")
depth--;
}
if(depth !==0) return false;
return true;
}
console.log(checkParanthesis("() test"));
Question:
But how can I check for multiple parenthesis elements? (){}[]
For example,
Input:
"[(]) abcd" // should return false
"[{()}] test" // should return true
Should return false (Not true)
Use an array as a stack to keep track of unresolved opening braces:
function checkParanthesis(str){
var stack=[];
for(var i=0; i<str.length; i++){
if(str[i] == "(" || str[i] == "{" || str[i] == "[")
stack.push(str[i]);
else if(str[i] == ")") {
if(stack.pop() != "(") { return false; }
}
else if(str[i] == "}") {
if(stack.pop() != "{") { return false; }
}
else if(str[i] == "]") {
if(stack.pop() != "[") { return false; }
}
}
return !stack.length;
}
You can probably clean this up to be more readable, but basically:
Every time you find an opening brace, add it to the stack.
Every time you see a closing brace, pop the stack and see if the stack's top is a matching opening brace.
If it's not, you have a mismatch, so you can immediately return false.
If you make it to the end, you didn't spot any errors, return true if the stack is empty (i.e., stack.length is 0).
(Note I also changed your i in str loop since it will iterate over properties on String.prototype.)
One cleanup you could do (but I'm not sure if this makes the code more readable or not) would be to put the brace pairings in an object, with the closing character as the key and the corresponding opening character as the value. Then, see if the current character exists as a key in the object, and if so, pop the stack and see if the value for that key matches:
function checkParanthesis(str){
var stack=[];
var brace_pairings = { ")":"(", "}":"{", "]":"[" };
for(var i=0; i<str.length; i++){
if(str[i] == "(" || str[i] == "{" || str[i] == "[") {
stack.push(str[i]);
} else if(str[i] in brace_pairings) {
if(stack.pop() != brace_pairings[str[i]]) { return false; }
}
}
return !stack.length;
}
Rather than a counter, you could use a stack, pushing a token onto the stack when an opening bracket is seen, and popping from the stack when the correct closing bracket is seen. If a closing bracket is encountered when a different type of bracket is at the top of the stack, or when the stack is empty, the string is unbalances.
Something like this (not polished and tested):
function checkParanthesis(str){
var stack = [];
var open;
for(var i in str){
if(str[i] == "(" || str[i] == "{" || str[i] == "[") {
stack.push(str[i]);
}
else if(str[i] == ")" || str[i] == "}" || str[i] == "]") {
if ( stack.length == 0 ) {
return false;
}
open = stack.pop();
if (
( open == '(' && str[i] != ')' )
|| ( open == '[' && str[i] != ']' )
|| ( open == '{' && str[i] != '}' )
) {
return false;
}
}
}
if ( stack.length > 0 ) {
return false;
}
return true;
}
Use a regex to get all the braces in a match() array...then remove each end of array testing each set
function checkParanthesis(str) {
//hashmap to compare open/close braces
var closers = {'[': ']','(': ')','{': '}'};
// create braces array
var parStack = str.match(/\(|\{|\[|\)|\}|\]/g) || [];
if (parStack.length % 2 !== 0) {//must have even number
return false;
} else {
while (parStack.length) {
// check each end of array against each other.
if (closers[parStack.shift()] !== parStack.pop()) {
//mismatch , we're done
return false;
}
}
return true;
}
}
console.log('no braces ', checkParanthesis("test"));
console.log('matched ', checkParanthesis("() test"));
console.log('mis matched ',checkParanthesis("[(]) abcd")); // should return false
console.log('matched ',checkParanthesis("[{()}] test"));
The array/stack/counter approach reads the string from left to right. Another approach is to work from the inside out.
function checkParanthesis(str){
while ( str.indexOf('()')>=0 || str.indexOf('[]')>=0 || str.indexOf('{}')>=0 ) {
str = str.replace('()','').replace('[]','').replace('{}','');
}
return str.length===0;
}
You could use regular expressions for the replace part to do a global replace and loop fewer times. The downside is that you'd need to escape everything in sight: str.replace(/\(\)/g,'') et.c.
Since I was working on leetCode and find your question, I found this article was written pretty clear about the problem and I tested it and I quoted here:
Click here!
Parenthesis Matching Problem in JavaScript
let isMatchingBrackets = function (str) {
let stack = [];
let map = {
'(': ')',
'[': ']',
'{': '}'
}
for (let i = 0; i < str.length; i++) {
// If character is an opening brace add it to a stack
if (str[i] === '(' || str[i] === '{' || str[i] === '[' ) {
stack.push(str[i]);
}
// If that character is a closing brace, pop from the stack, which will also reduce the length of the stack each time a closing bracket is encountered.
else {
let last = stack.pop();
//If the popped element from the stack, which is the last opening brace doesn’t match the corresponding closing brace in the map, then return false
if (str[i] !== map[last]) {return false};
}
}
// By the completion of the for loop after checking all the brackets of the str, at the end, if the stack is not empty then fail
if (stack.length !== 0) {return false};
return true;
}
I am definitely stuck on this one and could use your help. What do you think?
var swapcase = function(str) {
var string = str.split("");
for (var i = 0; i < string.length; i++) {
if (str.charAt(i) <= 'a' && str.charAt(i) >= 'z') {
str.charAt(i).toUppercase();
} else if (str.charAt(i) <= 'A' && str.charAt(i) >= 'Z') {
str.charAt(i).toLowercase();
}
}
str = letters.join("");
console.log(str);
var text = "Life is 10% what happens to you, and 90% of how you REACT to it";
swapCase(text);
};
Your code has a few errors:
JavaScript is case-sensitive: is the function called swapcase or swapCase?
string isn't a great variable name, especially because you refer to it by a different name (letters) at the end of the function.
Your comparison operators are inverted. Try >= 'a', <= 'z', etc.
JavaScript is case-sensitive: you should be calling toUpperCase and toLowerCase.
You're never calling swapCase aside from inside the function itself.
The fixed version:
var swapCase = function(str) {
var letters = str.split("");
for (var i = 0; i < letters.length; i++) {
if (str.charAt(i) >= 'a' && str.charAt(i) <= 'z') {
letters[i] = str.charAt(i).toUpperCase();
} else if (str.charAt(i) >= 'A' && str.charAt(i) <= 'Z') {
letters[i] = str.charAt(i).toLowerCase();
}
}
str = letters.join("");
console.log(str);
return str;
};
var text = "Life is 10% what happens to you, and 90% of how you REACT to it";
swapCase(text);
An easier way to test the case of a character would be:
if (str.charAt(i).toLowerCase() === str.charAt(i)) {
// Character is lower case or not a letter
} else {
// Character is upper case
}