[regex] Regex to match string containing two names in any order

I need logical AND in regex.

something like

jack AND james

agree with following strings

  • 'hi jack here is james'

  • 'hi james here is jack'

This question is related to regex string

The answer is


Try:

james.*jack

If you want both at the same time, then or them:

james.*jack|jack.*james

You can make use of regex's quantifier feature since lookaround may not be supported all the time.

(\bjames\b){1,}.*(\bjack\b){1,}|(\bjack\b){1,}.*(\bjames\b){1,}

Explanation of command that i am going to write:-

. means any character, digit can come in place of .

* means zero or more occurrences of thing written just previous to it.

| means 'or'.

So,

james.*jack

would search james , then any number of character until jack comes.

Since you want either jack.*james or james.*jack

Hence Command:

jack.*james|james.*jack

Its short and sweet

(?=.*jack)(?=.*james)

Test Cases:

_x000D_
_x000D_
[
  "xxx james xxx jack xxx",
  "jack xxx james ",
  "jack xxx jam ",
  "  jam and jack",
  "jack",
  "james",
]
.forEach(s => console.log(/(?=.*james)(?=.*jack)/.test(s)) )
_x000D_
_x000D_
_x000D_


Vim has a branch operator \& that is useful when searching for a line containing a set of words, in any order. Moreover, extending the set of required words is trivial.

For example,

/.*jack\&.*james

will match a line containing jack and james, in any order.

See this answer for more information on usage. I am not aware of any other regex flavor that implements branching; the operator is not even documented on the Regular Expression wikipedia entry.


The expression in this answer does that for one jack and one james in any order.

Here, we'd explore other scenarios.

METHOD 1: One jack and One james

Just in case, two jack or two james would not be allowed, only one jack and one james would be valid, we can likely design an expression similar to:

^(?!.*\bjack\b.*\bjack\b)(?!.*\bjames\b.*\bjames\b)(?=.*\bjames\b)(?=.*\bjack\b).*$

Here, we would exclude those instances using these statements:

(?!.*\bjack\b.*\bjack\b)

and,

(?!.*\bjames\b.*\bjames\b)

RegEx Demo 1

We can also simplify that to:

^(?!.*\bjack\b.*\bjack\b|.*\bjames\b.*\bjames\b)(?=.*\bjames\b|.*\bjack\b).*$

RegEx Demo 2


If you wish to simplify/update/explore the expression, it's been explained on the top right panel of regex101.com. You can watch the matching steps or modify them in this debugger link, if you'd be interested. The debugger demonstrates that how a RegEx engine might step by step consume some sample input strings and would perform the matching process.


RegEx Circuit

jex.im visualizes regular expressions:

enter image description here

Test

_x000D_
_x000D_
const regex = /^(?!.*\bjack\b.*\bjack\b|.*\bjames\b.*\bjames\b)(?=.*\bjames\b|.*\bjack\b).*$/gm;
const str = `hi jack here is james
hi james here is jack
hi james jack here is jack james
hi jack james here is james jack
hi jack jack here is jack james
hi james james here is james jack
hi jack jack jack here is james
`;
let m;

while ((m = regex.exec(str)) !== null) {
    // This is necessary to avoid infinite loops with zero-width matches
    if (m.index === regex.lastIndex) {
        regex.lastIndex++;
    }
    
    // The result can be accessed through the `m`-variable.
    m.forEach((match, groupIndex) => {
        console.log(`Found match, group ${groupIndex}: ${match}`);
    });
}
_x000D_
_x000D_
_x000D_


METHOD 2: One jack and One james in a specific order

The expression can be also designed for first a james then a jack, similar to the following one:

^(?!.*\bjack\b.*\bjack\b|.*\bjames\b.*\bjames\b)(?=.*\bjames\b.*\bjack\b).*$

RegEx Demo 3

and vice versa:

^(?!.*\bjack\b.*\bjack\b|.*\bjames\b.*\bjames\b)(?=.*\bjack\b.*\bjames\b).*$

RegEx Demo 4


You can do:

\bjack\b.*\bjames\b|\bjames\b.*\bjack\b