Wildcard string comparison in Javascript
JavascriptStringComparisonJavascript Problem Overview
Let's say I have an array with many Strings Called "birdBlue"
, "birdRed"
and some other animals like "pig1"
, "pig2"
).
Now I run a for loop that goes through the array and should return all birds. What comparison would make sense here?
Animals == "bird*"
was my first idea but doesn't work. Is there a way to use the operator * (or is there something similar to use?
Javascript Solutions
Solution 1 - Javascript
I think you meant something like "*" (star) as a wildcard for example:
- "a*b" => everything that starts with "a" and ends with "b"
- "a*" => everything that starts with "a"
- "*b" => everything that ends with "b"
- "*a*" => everything that has an "a" in it
- "*a*b*"=> everything that has an "a" in it, followed by anything, followed by a "b", followed by anything
or in your example: "bird*" => everything that starts with bird
I had a similar problem and wrote a function with RegExp:
//Short code
function matchRuleShort(str, rule) {
var escapeRegex = (str) => str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
return new RegExp("^" + rule.split("*").map(escapeRegex).join(".*") + "$").test(str);
}
//Explanation code
function matchRuleExpl(str, rule) {
// for this solution to work on any string, no matter what characters it has
var escapeRegex = (str) => str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
// "." => Find a single character, except newline or line terminator
// ".*" => Matches any string that contains zero or more characters
rule = rule.split("*").map(escapeRegex).join(".*");
// "^" => Matches any string with the following at the beginning of it
// "$" => Matches any string with that in front at the end of it
rule = "^" + rule + "$"
//Create a regular expression object for matching string
var regex = new RegExp(rule);
//Returns true if it finds a match, otherwise it returns false
return regex.test(str);
}
//Examples
alert(
"1. " + matchRuleShort("bird123", "bird*") + "\n" +
"2. " + matchRuleShort("123bird", "*bird") + "\n" +
"3. " + matchRuleShort("123bird123", "*bird*") + "\n" +
"4. " + matchRuleShort("bird123bird", "bird*bird") + "\n" +
"5. " + matchRuleShort("123bird123bird123", "*bird*bird*") + "\n" +
"6. " + matchRuleShort("s[pe]c 3 re$ex 6 cha^rs", "s[pe]c*re$ex*cha^rs") + "\n" +
"7. " + matchRuleShort("should not match", "should noo*oot match") + "\n"
);
If you want to read more about the used functions:
Solution 2 - Javascript
You should use RegExp (they are awesome) an easy solution is:
if( /^bird/.test(animals[i]) ){
// a bird :D
}
Solution 3 - Javascript
Converter
This function convert wildcard to regexp and make test (it supports .
and *
wildcharts)
function wildTest(wildcard, str) {
let w = wildcard.replace(/[.+^${}()|[\]\\]/g, '\\$&'); // regexp escape
const re = new RegExp(`^${w.replace(/\*/g,'.*').replace(/\?/g,'.')}$`,'i');
return re.test(str); // remove last 'i' above to have case sensitive
}
function wildTest(wildcard, str) {
let w = wildcard.replace(/[.+^${}()|[\]\\]/g, '\\$&'); // regexp escape
const re = new RegExp(`^${w.replace(/\*/g,'.*').replace(/\?/g,'.')}$`,'i');
return re.test(str); // remove last 'i' above to have case sensitive
}
// Example usage
let arr = ["birdBlue", "birdRed", "pig1z", "pig2z", "elephantBlua" ];
let resultA = arr.filter( x => wildTest('biRd*', x) );
let resultB = arr.filter( x => wildTest('p?g?z', x) );
let resultC = arr.filter( x => wildTest('*Blu?', x) );
console.log('biRd*',resultA);
console.log('p?g?z',resultB);
console.log('*Blu?',resultC);
Solution 4 - Javascript
You could use Javascript's substring method. For example:
var list = ["bird1", "bird2", "pig1"]
for (var i = 0; i < list.length; i++) {
if (list[i].substring(0,4) == "bird") {
console.log(list[i]);
}
}
Which outputs:
bird1
bird2
Basically, you're checking each item in the array to see if the first four letters are 'bird'. This does assume that 'bird' will always be at the front of the string.
So let's say your getting a pathname from a URL :
Let's say your at bird1?=letsfly - you could use this code to check the URL:
var listOfUrls = [ "bird1?=letsfly", "bird", "pigs?=dontfly", ]
for (var i = 0; i < list.length; i++) {
if (listOfUrls[i].substring(0,4) === 'bird') {
// do something
}
}
The above would match the first to URL's, but not the third (not the pig). You could easily swap out url.substring(0,4)
with a regex, or even another javascript method like .contains()
Using the .contains()
method might be a little more secure. You won't need to know which part of the URL 'bird' is at. For instance:
var url = 'www.example.com/bird?=fly'
if (url.contains('bird')) {
// this is true
// do something
}
Solution 5 - Javascript
var searchArray = function(arr, str){
// If there are no items in the array, return an empty array
if(typeof arr === 'undefined' || arr.length === 0) return [];
// If the string is empty return all items in the array
if(typeof str === 'undefined' || str.length === 0) return arr;
// Create a new array to hold the results.
var res = [];
// Check where the start (*) is in the string
var starIndex = str.indexOf('*');
// If the star is the first character...
if(starIndex === 0) {
// Get the string without the star.
str = str.substr(1);
for(var i = 0; i < arr.length; i++) {
// Check if each item contains an indexOf function, if it doesn't it's not a (standard) string.
// It doesn't necessarily mean it IS a string either.
if(!arr[i].indexOf) continue;
// Check if the string is at the end of each item.
if(arr[i].indexOf(str) === arr[i].length - str.length) {
// If it is, add the item to the results.
res.push(arr[i]);
}
}
}
// Otherwise, if the star is the last character
else if(starIndex === str.length - 1) {
// Get the string without the star.
str = str.substr(0, str.length - 1);
for(var i = 0; i < arr.length; i++){
// Check indexOf function
if(!arr[i].indexOf) continue;
// Check if the string is at the beginning of each item
if(arr[i].indexOf(str) === 0) {
// If it is, add the item to the results.
res.push(arr[i]);
}
}
}
// In any other case...
else {
for(var i = 0; i < arr.length; i++){
// Check indexOf function
if(!arr[i].indexOf) continue;
// Check if the string is anywhere in each item
if(arr[i].indexOf(str) !== -1) {
// If it is, add the item to the results
res.push(arr[i]);
}
}
}
// Return the results as a new array.
return res;
}
var birds = ['bird1','somebird','bird5','bird-big','abird-song'];
var res = searchArray(birds, 'bird*');
// Results: bird1, bird5, bird-big
var res = searchArray(birds, '*bird');
// Results: somebird
var res = searchArray(birds, 'bird');
// Results: bird1, somebird, bird5, bird-big, abird-song
There is an long list of caveats to a method like this, and a long list of 'what ifs' that are not taken into account, some of which are mentioned in other answers. But for a simple use of star syntax this may be a good starting point.
Solution 6 - Javascript
I used the answer by @Spenhouet and added more "replacements"-possibilities than "*". For example "?". Just add your needs to the dict in replaceHelper
.
/**
* @param {string} str
* @param {string} rule
* checks match a string to a rule
* Rule allows * as zero to unlimited numbers and ? as zero to one character
* @returns {boolean}
*/
function matchRule(str, rule) {
const escapeRegex = (str) => str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
return new RegExp("^" + replaceHelper(rule, {"*": "\\d*", "?": ".?"}, escapeRegex) + "$").test(str);
}
function replaceHelper(input, replace_dict, last_map) {
if (Object.keys(replace_dict).length === 0) {
return last_map(input);
}
const split_by = Object.keys(replace_dict)[0];
const replace_with = replace_dict[split_by];
delete replace_dict[split_by];
return input.split(split_by).map((next_input) => replaceHelper(next_input, replace_dict, last_map)).join(replace_with);
}
Solution 7 - Javascript
When you have a rule
wildcard string and a text
string to match:
function wcMatch(rule, text) {
return (new RegExp('^' + rule.replaceAll(/([.+?^=!:${}()|\[\]\/\\])/g, "\\$1").replaceAll('*', '(.*)') + '$')).test(text)
}
First replaceAll
escapes special characters, second one replaces *
with (.*)
(an expression means "any zero or more characters")
For example, a string *&utm_*
will be turned into an expression /^(.*)\&utm_(.*)$/
Solution 8 - Javascript
We Can Simply Use The String.includes()
& Array.filter()
methods in conjuction for this.
let items = ["bird1", "bird2", "pig1", "pig2"]
let birds = items.filter((item) => {
return item.includes("bird")
})
let pigs = items.filter((item) => {
return item.includes("pig")
})
The filter()
method creates a new array with all elements that pass the test implemented by the provided function.
The includes()
method performs a case-sensitive search to determine whether one string may be found within another string, returning true
or false
as appropriate.
Reference: Array.prototype.filter() and String.prototype.includes()
Solution 9 - Javascript
if(mas[i].indexOf("bird") == 0)
//there is bird
You.can read about indexOf here: http://www.w3schools.com/jsref/jsref_indexof.asp
Solution 10 - Javascript
Instead Animals == "bird*"
Animals = "bird*"
should work.