5

I want to check if a string have all input keywords in any order of the string. In much cases, the keywords are in any order, but exists in string.

Example(this is what I expect):

// Same order and have all keywords
"Hello world!".contains( "hello world" )       // true

// Same order and have all keywords
"Hello all in the world!".contains( "hello world" )       // true

// Any order but have all keywords
"Hello world!".contains( "world hello" )       // true

// Same order and all keywords
"Hello world!".contains( "worl hell" )         // true

// Have all keywords in any order
"Hello world!".contains( "world" )             // true

// No contains all keywords
"Hello world!".contains( "where you go" )      // false

// No contains all keywords
"Hello world!".contains( "z" )                 // false

// No contains all keywords
"Hello world!".contains( "z1 z2 z3" )          // false

// Contains all keywords in any order
"Hello world!".contains( "wo" )                // true

I try with:

/(?=\bhello\b)(?=\bworld\b)/i.test("hello world")      // false
/(?=.*?hello.*?)(?=.*?world.*?)/i.test("hello world")  // false
/^(?=\bhello\b)(?=\bworld\b).*?$/i.test("hello world") // false

I created some functions like:

// escape string to use in regexp
String.prototype.escape = function () {
    return this.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&")
};
// check if empty string
String.prototype.isEmpty = function () {
    return this.length === 0;
};
// check if contain keywords...
String.prototype.contains = function (keywords) {
    var value  = '^(?=\\b' + keywords
        .escape()
        .replace(/(^\s+|\s+$)/ig, '')
        .replace(/\s+/, ' ')
        .split(/\s+/)
        .join('.*?)(?=.*?') + ').*$',
    reg = new RegExp(value, 'i'),
    text = this;
    return reg.test( this );
};

Thanks

Olaf Erlandsen
  • 5,817
  • 9
  • 41
  • 73
  • Any or All of the keywords? – LukStorms Jan 19 '17 at 17:31
  • @LukStorms i want check if have all keywords in any order. Thanks – Olaf Erlandsen Jan 19 '17 at 17:32
  • @I.G.Pascual no, no is duplicated. See this example: `"Hello all in the world!".contains( "hello world" )` I want this return `true` because have all keywords in any order – Olaf Erlandsen Jan 19 '17 at 17:58
  • @OlafErlandsen Its confusing. `"Hello world!".contains( "world" ) `. This example has just one keyword and the output is true. – pratZ Jan 19 '17 at 18:00
  • @pratZ yes, if you have only one keywords, so only search this keyword in any order, but if you have more than one, so, need search all keywords in any order. is invalid: `"hello world".contains("planet")`, but is valid `"hello world".contains("world")` and is valid `"hello all there!".contains("hello there")` but not is valid `"hello world".contains("take on me take on me")` – Olaf Erlandsen Jan 19 '17 at 18:03
  • Ok I get it, but then your question should explain that you are not only looking for keywords, but __also words containing the keywords__, sort of like a Search engine works... You are not trying to implement a Google-like search with a Regexp aren't you? :P – I.G. Pascual Jan 19 '17 at 21:10
  • 1
    Oh, BTW, __Don't modify String.prototype!!!__ https://books.google.es/books?id=J5RCV8yM7sEC&pg=PA103&lpg=PA103&dq=don+modify+objects+you+don+own&source=bl&ots=TE-zGCdVKs&sig=Q4fP8Jm9FtduqQbSJdV_6Yvixo0&hl=es&sa=X&ved=0ahUKEwjPj8-QlM_RAhUD6xQKHeNHCu8Q6AEIKDAE#v=onepage&q=don%20modify%20objects%20you%20don%20own&f=false , what you're doing is a complete madness, all the other js libraries you import depending on it could stop working!! – I.G. Pascual Jan 19 '17 at 21:30

6 Answers6

6

You mean an unordered list of keywords: Regex - match multiple unordered words in a string, but removing the last \b part of each regex token

/(?=.*?\bhello)(?=.*?\bworld).*/i

With these type of regex all your test should pass now.

Check it in http://regexr.com/3f3ru

i makes it to ignore case sensitive, in case you need to check also Hello, wOrld, etc

Community
  • 1
  • 1
I.G. Pascual
  • 5,818
  • 5
  • 42
  • 58
4

The answer from I.G. Pascual shows how to construct a regex that solves the OP's problem. Below is working code demonstrating how to build such regexes dynamically, passing all the test cases from the OP.

function buildRegEx(str, keywords){
  return new RegExp("(?=.*?\\b" + 
    keywords
      .split(" ")
      .join(")(?=.*?\\b") +                     
    ").*", 
    "i"
  );
}

function test(str, keywords, expected){
  var result = buildRegEx(str, keywords).test(str) === expected
  console.log(result ? "Passed" : "Failed");
}

// Same order and have all keywords 
test("Hello world!", "hello world", true);
// Same order and have all keywords 
test("Hello all in the world!", "hello world", true);
// Any order but have all keywords 
test("Hello world!", "world hello", true);
// Same order and all keywords 
test("Hello world!", "worl hell", true);
// Have all keywords in any order 
test("Hello world!", "world", true);
// No contains all keywords 
test("Hello world!", "where you go", false);
// No contains all keywords
test("Hello world!", "z", false);
// No contains all keywords 
test("Hello world!", "z1 z2 z3", false);
// Contains all keywords in any order 
test("Hello world!", "wo", true);
Community
  • 1
  • 1
Tomas Langkaas
  • 4,551
  • 2
  • 19
  • 34
1

An alternative to the lookahead-based option would be:

String.prototype.contains = function (keywordsStr) {
    var keywords = keywordsStr.split(/\s+/);
    return keywords.every(function(keyword)) {
        var reg = new RegExp(keyword.escape());
        return reg.test(this);
    }, this);
};
lleaff
  • 4,249
  • 17
  • 23
  • You answer is exlactly to @IGPascual. I want check if a string have all input keywords in any order. Please, see my examples. Thanks – Olaf Erlandsen Jan 19 '17 at 17:37
  • Indeed, my bad. I've updated my answer to provide an alternative to @I.G. Pascual's answer. I'd be interested to know which is the fastest one as the JS RegExp engine can be pretty slow. – lleaff Jan 19 '17 at 17:49
  • no need for `\b` as `wo` is contained in `Hello world`. See the question. – ibrahim mahrir Jan 19 '17 at 18:55
  • @ibrahim mahrir Oh true, the `"\\b"` in OP's example confused me. – lleaff Jan 19 '17 at 19:51
1
String.prototype.contains = function(string){    
    var keywords = string.split(" ");
    var contain = true;

    for(var i = 0; i < keywords.length && contain; i++){
        if(keywords[i] == "") continue;

        var regex = new RegExp(keywords[i], "i");
        contain = contain && regex.test(this);
    }

    return contain;
}
ibrahim mahrir
  • 31,174
  • 5
  • 48
  • 73
0

It's easy way to use .match() method to string. You can try this

Example:

var re = /(hello|world)/i;
var str = "Hello world!"; 
console.log('Do we found something?', Boolean(str.match(re)));

// for other
var re = /(hello|world)/i;       // true
var re = /(world|hello)/i;       // true
var re = /(worl|hell)/i;         // true
var re = /(this|is|my|world)/i;  // true
var re = /(where|you|go)/i;      // false
var re = /(z)/i;                 // false
var re = /(z1|z2|z3)/i;          // false
var re = /(wo)/i;                // true
Sid Mhatre
  • 3,272
  • 1
  • 19
  • 38
  • This check if have one of `n` keywords. No if hace all `n` keywords. – Olaf Erlandsen Jan 19 '17 at 17:55
  • you can try this as already suggested `/(?=.*?\bworld\b)(?=.*?\bhello\b).*/i.test('Hello world!')` – Sid Mhatre Jan 19 '17 at 18:12
  • You want to check your string contain all the keywords in any oder you can check using String match() Method `var regexp = /[world hello]/gi; var matches_array = str.match(regexp); alert(matches_array);` and compare ` matches_array` length with regex string length – Sid Mhatre Jan 19 '17 at 18:30
0

result.filter(camp => search.map(keyword => camp.name.includes(keyword)).reduce((acc, curr) => acc && curr, true));

saransh mehra
  • 157
  • 2
  • 9