Search code examples
javascriptregexposix

How to check if contains all keywords in any order of string? RegExp Javascript


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


Solution

  • 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);