This question already has answers here:
How to check whether a string contains a substring in JavaScript?
(3 answers)
Closed 5 years ago.
I have a shopping cart that displays product options in a dropdown menu and if they select "yes", I want to make some other fields on the page visible.
The problem is that the shopping cart also includes the price modifier in the text, which can be different for each product. The following code works:
$(document).ready(function() {
$('select[id="Engraving"]').change(function() {
var str = $('select[id="Engraving"] option:selected').text();
if (str == "Yes (+ $6.95)") {
$('.engraving').show();
} else {
$('.engraving').hide();
}
});
});
However I would rather use something like this, which doesn't work:
$(document).ready(function() {
$('select[id="Engraving"]').change(function() {
var str = $('select[id="Engraving"] option:selected').text();
if (str *= "Yes") {
$('.engraving').show();
} else {
$('.engraving').hide();
}
});
});
I only want to perform the action if the selected option contains the word "Yes", and would ignore the price modifier.
Like this:
if (str.indexOf("Yes") >= 0)
...or you can use the tilde operator:
if (~str.indexOf("Yes"))
This works because indexOf() returns -1 if the string wasn't found at all.
Note that this is case-sensitive.
If you want a case-insensitive search, you can write
if (str.toLowerCase().indexOf("yes") >= 0)
Or:
if (/yes/i.test(str))
The latter is a regular expression or regex.
Regex breakdown:
/ indicates this is a regex
yes means that the regex will find those exact characters in that exact order
/ ends the regex
i sets the regex as case-insensitive
.test(str) determines if the regular expression matches str
To sum it up, it means it will see if it can find the letters y, e, and s in that exact order, case-insensitively, in the variable str
You could use search or match for this.
str.search( 'Yes' )
will return the position of the match, or -1 if it isn't found.
It's pretty late to write this answer, but I thought of including it anyhow. String.prototype now has a method includes which can check for substring. This method is case sensitive.
var str = 'It was a good date';
console.log(str.includes('good')); // shows true
console.log(str.includes('Good')); // shows false
To check for a substring, the following approach can be taken:
if (mainString.toLowerCase().includes(substringToCheck.toLowerCase())) {
// mainString contains substringToCheck
}
Check out the documentation to know more.
Another way:
var testStr = "This is a test";
if(testStr.contains("test")){
alert("String Found");
}
** Tested on Firefox, Safari 6 and Chrome 36 **
ECMAScript 6 introduces String.prototype.includes, previously named contains.
It can be used like this:
'foobar'.includes('foo'); // true
'foobar'.includes('baz'); // false
It also accepts an optional second argument which specifies the position at which to begin searching:
'foobar'.includes('foo', 1); // false
'foobar'.includes('bar', 1); // true
It can be polyfilled to make it work on old browsers.
The includes() method determines whether one string may be found within another string, returning true or false as appropriate.
Syntax :-string.includes(searchString[, position])
searchString:-A string to be searched for within this string.
position:-Optional. The position in this string at which to begin searching for searchString; defaults to 0.
string = 'LOL';
console.log(string.includes('lol')); // returns false
console.log(string.includes('LOL')); // returns true
You can use this Polyfill in ie and chrome
if (!('contains' in String.prototype)) {
String.prototype.contains = function (str, startIndex) {
"use strict";
return -1 !== String.prototype.indexOf.call(this, str, startIndex);
};
}
If you are capable of using libraries, you may find that Lo-Dash JS library is quite useful. In this case, go ahead and check _.contains() (replaced by _.includes() as of v4).
(Note Lo-Dash convention is naming the library object _.
Don't forget to check installation in the same page to set it up for your project.)
_.contains("foo", "oo"); // → true
_.contains("foo", "bar"); // → false
// Equivalent with:
_("foo").contains("oo"); // → true
_("foo").contains("bar"); // → false
In your case, go ahead and use:
_.contains(str, "Yes");
// or:
_(str).contains("Yes");
..whichever one you like better.
I know that best way is str.indexOf(s) !== -1; http://hayageek.com/javascript-string-contains/
I suggest another way(str.replace(s1, "") !== str):
var str = "Hello World!", s1 = "ello", s2 = "elloo";
alert(str.replace(s1, "") !== str);
alert(str.replace(s2, "") !== str);
You can also check if the exact word is contained in a string. E.g.:
function containsWord(haystack, needle) {
return (" " + haystack + " ").indexOf(" " + needle + " ") !== -1;
}
Usage:
containsWord("red green blue", "red"); // true
containsWord("red green blue", "green"); // true
containsWord("red green blue", "blue"); // true
containsWord("red green blue", "yellow"); // false
This is how jQuery does its hasClass method.
you can define an extension method and use it later.
String.prototype.contains = function(it)
{
return this.indexOf(it) != -1;
};
so that you can use in your page anywhere like:
var str="hello how are you";
str.contains("are");
which returns true.
Refer below post for more extension helper methods.
Javascript helper methods
None of the above worked for me as there were blank spaces but this is what I did
tr = table.getElementsByTagName("tr");
for (i = 0; i < tr.length; i++) {
td = tr[i].getElementsByTagName("td")[0];
bottab.style.display="none";
bottab2.style.display="none";
if (td) {
var getvar=td.outerText.replace(/\s+/, "") ;
if (getvar==filter){
tr[i].style.display = "";
}else{
tr[i].style.display = "none";
}
}
}
Related
Hello I'm trying to understand recursion in JavaScript.
So far I have:
function countVowels(string) {
let vowelCount = 0;
// if we're not at the end of the string,
// and if the character in the string is a vowel
if (string.length - 1 >= 0 && charAt(string.length -1) === "aeiouAEIOU") {
//increase vowel count every time we iterate
countVowels(vowelCount++);
}
return vowelCount;
}
First of all, this is giving me issues because charAt is not defined. How else can I say "the character at the current index" while iterating?
I can't use a for-loop - I have to use recursion.
Second of all, am I using recursion correctly here?
countVowels(vowelCount++);
I'm trying to increase the vowel count every time the function is called.
Thanks for your guidance.
If you're interested, here is a version that does not keep track of the index or count, which might illuminate more about how the recursion can be done.
function countVowels(string) {
if (!string.length) return 0;
return (
"aeiou".includes(string.charAt(0).toLowerCase()) +
countVowels(string.substr(1))
);
}
console.log(countVowels("")); // 0
console.log(countVowels("abcde")); // 2
console.log(countVowels("eee")); // 3
// Note that:
console.log('"hello".substr(1)', "hello".substr(1)) // ello
console.log('"hello".charAt(0)', "hello".charAt(0)) // h
console.log('"aeiou".includes("a")', "aeiou".includes("a")) // true
console.log('"a".includes("aeiou")', "a".includes("aeiou")) // false
Our base case is that the string is empty, so we return 0.
Otherwise, we check if the first character in the string is a vowel (true == 1 and false == 0 in javascript) and sum that with counting the next (smaller by one) string.
You are making two mistakes:
You should have three parameters string , count(count of vowels) and current index i.
You should use includes() instead of comparing character with "aeiouAEIOU"
function countVowels(string,count= 0,i=0) {
if(!string[i]) return count
if("aeiou".includes(string[i].toLowerCase())) count++;
return countVowels(string,count,i+1);
}
console.log(countVowels("abcde")) //2
As asked by OP in comments "Can you please explain why it'sif("aeiou".includes(string[i].toLowerCase())) instead of if(string[i].includes("aeiou".toLowerCase()))"
So first we should know what includes does. includes() checks for string if it includes a certain substring passed to it or not. The string on which the method will be used it will be larger string and the value passed to includes() be smaller one.
Wrong one.
"a".includes('aeiou') //checking if 'aeiou' is present in string "a" //false
Correct one.
"aeiou".includes('a') //checking if 'a' is present in string "aeiou" //true
One possible solution would be:
function countVowels(string, number) {
if (!string) return number;
return countVowels(string.slice(1), 'aeiouAEIOU'.includes(string[0])? number + 1 : number);
}
// tests
console.log('abc --> ' + countVowels('abc', 0));
console.log('noor --> ' + countVowels('noor', 0));
console.log('hi --> ' + countVowels('hi', 0));
console.log('xyz --> ' + countVowels('xyz', 0));
and you should call your function like: countVowels('abc', 0)
Notes about your solution:
you always reset vowelCount inside your function, this usually does not work with recursion.
you defined your function to accept a string, but recall it with an integer in countVowels(vowelCount++); this it will misbehave.
always remember that you have to define your base case first thing in your recursion function, to make sure that you will stop sometime and not generate an infinite loop.
Alternative ES6 solution using regex and slice() method. Regex test() method will return true for vowels and as stated in a previous answer JavaScript considers true + true === 2.
const countVowels = str => {
return !str.length ? 0 : /[aeiou]/i.test(str[0]) + countVowels(str.slice(1));
}
Can someone please explain this strange behavior in Javascript? When I do comparisons using the match() method I don't get the expected result.
var mat_1 = "wpawn";
var mat_2 = "wRook";
//compare both; do they have the same first letter?
alert(mat_1.match(/^\w/) + " seems equal to " + mat_2.match(/^\w/));
if (mat_1.match(/^\w/) === mat_2.match(/^\w/)) {
alert("They are really equal")
}
//another approach
if (mat_1[0] === mat_2[0]) {
alert("Yes! Equals")
}
match produces an array. You should really use an array comparison function, but for the sake of simple demonstration, try this - the first match value is selected and compared. All 3 alerts are triggered:
var mat_1 = "wpawn";
var mat_2 = "wRook";
//compare both; do they have the same first letter?
alert(mat_1.match(/^\w/)+" seems equal to "+mat_2.match(/^\w/));
if(mat_1.match(/^\w/)[0] === mat_2.match(/^\w/)[0]){alert("They are really equal")}
//another approach
if(mat_1[0] === mat_2[0]){alert("Yes! Equals")}
Match returns an array of matches:
String.prototype.match(pattern: Regex): Array<string>
Your first evaluation will always fail as you are comparing two arrays.
This is the correct way for what you are trying to achieve.
'myWord'.match(/^\w/)[0] == 'mIsTeRy'.match(/^\w/)[0]
Although if you wanna truly use the regex to check the first letter, I wouldn't recommend it. Too much overhead for something too trivial (just my two cents).
Have fun coding! :)
in the following lines of code you are checking the variables mat_1 and mat_2 for whether both the words starts with 'w', btw match() returns an array
if (mat_1.match(/^\w/) === mat_2.match(/^\w/)) {
alert("They are really equal")
}
you can try something like
if (["w"] === ["w"]) {
console.log("seems equal");
} else {
console.log("not equal");
}
for array comparison you can check this post
what you have to do here is
if (["w"][0] === ["w"][0]) { // match for the elements in the array
console.log("seems equal");
} else {
console.log("not equal");
}
There is a box that has a css background-image. By jQuery I want to check the value of this background-image, and if it contain a specific name then console.log("done").
Here is my jQuery code:
var bgName = $(".leftBox").css("background-image");
if (bgName.search("Z3Escd") == 0){
console.log("done");
}
// Z3Escd is the name of my file that it must check.
Unfortunately it does not work. DEMO http://jsfiddle.net/danials/qU8W7/
Any idea to find some certain characters in the string?
Use this
var bgName = $(".leftBox").css("background-image");
if (bgName.search("Z3Escd") != -1){
console.log("done");
}
You should check if bgName.search result is >= 0. That's because String.search returns index of start of searched substring, and -1 if substring was not found.
You use your search function wrong.
The result of bgName.search is the startindex of your provided string in the to search string.
The best method would be to check if the string endswith:
String.prototype.endsWith = function(suffix) {
return this.indexOf(suffix, this.length - suffix.length) !== -1;
};
var bgName = $(".leftBox").css("background-image");
if (bgName.endsWith ("Z3Escd")){
console.log("done");
}
Using Jquery TableSorter, I am creating a custom parser to sort elapsed time <td>s that contain "'#' year(s) * '#' month(s)". When I use the function
$('.techtable td:nth-child(6)').each(function(){
// console.log($(this));
var that = $(this).text();
var myRegexp = /([\d]+) ([\w]+)(?: ([\d]+) ([\w]+))?/;
var match = myRegexp.exec($(this).text());
console.log(match);
});
from the command line, each index contains an array of length 5, looking like this:
["7 months", "7", "months", undefined, undefined]
to this:
["3 years 3 months", "3", "years", "3", "months"]
depending on whether or not the elapsed time has just a month or year element, and then the other. To parse the text, I use regex to gather each element, and then use JS to test whether there are multiple elements or not, and if 1 element only, then wheher it begins with "y" or "m", and return the number of months, so the parser can sort the <td>s by number of months in integer form.
The parser passes in each element into the function as parameter "s". when i try regex on "s" directly, it is not returning an array of length 5, it is truncating it to 3 (whether or not I am running the line that truncates it if index 3 is typeof 'undefined'). When I use the console to directly use this function:
$('.techtable td:nth-child(6)').each(function(){
// console.log($(this));
var that = $(this).text();
var myRegexp = /([\d]+) ([\w]+)(?: ([\d]+) ([\w]+))?/;
var match = myRegexp.exec($(this).text());
if (typeof match[3] == 'undefined') {match.length = 3;};
console.log(match);
});
the regex returns the arrays properly, with the array truncated if it only has 1 element (year or month). Here is the code for the custom parser:
var myRegexp = /([\d]+) ([\w]+)(?: ([\d]+) ([\w]+))?/;
var match = myRegexp.exec(s);
var order = [];
console.log(match);
if (typeof match[3] == 'undefined') {match.length = 3;};
// 1 element case:
// month
if (match.length = 3) {
if (match[2][0] == "m") {
order.push(match[1]);
}
// year
if (match[2][0] == "y") {
order.push(match[1]*12);
}
// both elements
} else {
order.push(match[1]*12 + match[3]);
}
s = order;
return s;
},
The fiddle is here. The Elapsed parser is second from the bottom of the JS panel. As you can see, since I can't get the months from the array (indices 4 and 5), I can not calculate the months, and thus the sorting only incorporates years, and the months are sorted by their original HTML placement. What am I missing? (I'm learning.... so direction is appreciated more than an fix, but I won't turn it down.)
Yes I realize the JS fiddle is loaded (first part is TableSorter, to maintain functionality for verification(click on headers to sort), but all you need to focus on is the last part of the code (reference the '//Table Sorter dateSorter' to see how a correct parser should look). The section '//Table Sorter elapsedSorter' is where my two attempts are, the first part is the working code I use in the console, and the seconde part is the parser, which is somehow deleting the last two indices in the array, thus loosing the month information to calculate.
Guess I'll have to add Regex, and a personal rating of 1, since I've wasted almost an entire day on this.
if (match.length = 3) {
You meant this?
if (match.length == 3) {
To help you further, when you write conditions with one constant and a variable, you can write them like this instead:
if (3 = match.length) {
This would now cause a JavaScript error instead of silently getting turned into an assignment that always yields true.
In JavaScript, 12 + '4' == '124', so you have to be careful with numbers and the + operator. In languages such as PHP you don't have this problem, because they have an operator for string concatenations ;-)
var myRegexp = /([\d]+) ([\w]+)(?: ([\d]+) ([\w]+))?/;
var match = myRegexp.exec(s);
var order = [];
if (typeof match[3] == 'undefined') {
if (match[2][0] == "m") {
order.push(parseInt(match[1]));
}
// year
if (match[2][0] == "y") {
order.push(parseInt(match[1])*12);
}
// both elements
} else {
order.push(parseInt(match[1])*12 + parseInt(match[3]));
}
s = order;
return s;
Btw use parseInt(x, 10) if you expect fields to have leading zeroes (which would otherwise result in 0 being returned). Thanks fudgey!
I want to test a given string against 20 or so regular expressions. What's a clean way to do this in Javascript? I'm more concerned about clean code and readability than efficiency (but I don't want it to be super slow either).
Right now I have:
if (href.indexOf('apple.com') > -1 ||
href.indexOf('google.com') > -1 ||
href.indexOf('yahoo.com') > -1 ||
href.indexOf('facebook.com') > -1) {
performDarkMagic()
}
But it's going to start looking kind of messy as that list grows.
Maybe I could just create an array of regular expressions and execute something like _.any() and apply regex.test on each?
Edit: the strings/regexes to match may become more complicated, I just used simple URLs to make the example readable.
Use the test function for regular expressions.
More information on regular expressions here.
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/RegExp
var re = /((google)|(facebook)|(yahoo)|(apple))\.com/;
re.test( str ); // returns true or false;
Test cases.
Live Demo Here:
http://jsfiddle.net/rkzXP/1/
var func = function( str ){
var re = /((google)|(facebook)|(yahoo)|(apple))\.com/;
return re.test( str );
};
test("test for valid values", function() {
equal( func("google.com"), true);
equal( func("facebook.com"), true);
equal( func("apple.com"), true);
});
test("test for invalid values", function() {
equal( func("googl.com"), false);
equal( func("faceook.com"), false);
equal( func("apple"), false);
});
So you can rewrite your code as the following.
var re = /((google)|(facebook)|(yahoo)|(apple))\.com/;
if( re.test(str) ){
performDarkMagic()
}
var patterns = ['apple.com', 'google.com', 'yahoo.com', 'facebook.com', ...]
var callFunc = false;
patterns.forEach(function(item){
if(href.indexOf(item) > -1){
callFunc = true;
break;
}
});
if(callFunc) {
performDarkMagic();
}
Yes, building an array and using .any() or .some() is just fine, especially when there will be more than 4 values:
if (["apple","google","yahoo","facebook"].some(host => href.includes(`${host}.com`)) {
performLightMagic();
}
Yet I can't see regexes there, there are just strings; so you could simplify using regex.test() to:
if (/apple\.com|google\.com|yahoo\.com|facebook\.com/.test(href)) { performLightMagic(); }
or even
if (/(apple|google|yahoo|facebook)\.com/.test(href)) { performLightMagic(); }
You could put each one in array then looping over each.
How I would do it: factor it out into a function. Put each regex in an array, loop over them and return true the first time indexOf > -1. If you reach the end of the loop return false.
Loop through a regex array and then do:
result=result AND (result_of_regex);
next;
after the loop return result