I need logical AND in regex.
something like
jack AND james
agree with following strings
\'hi jack here is
Its short and sweet
(?=.*jack)(?=.*james)
[
"xxx james xxx jack xxx",
"jack xxx james ",
"jack xxx jam ",
" jam and jack",
"jack",
"james",
]
.forEach(s => console.log(/(?=.*james)(?=.*jack)/.test(s)) )
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.
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)
We can also simplify that to:
^(?!.*\bjack\b.*\bjack\b|.*\bjames\b.*\bjames\b)(?=.*\bjames\b|.*\bjack\b).*$
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.
jex.im visualizes regular expressions:
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}`);
});
}
jack
and One james
in a specific orderThe 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).*$
and vice versa:
^(?!.*\bjack\b.*\bjack\b|.*\bjames\b.*\bjames\b)(?=.*\bjack\b.*\bjames\b).*$
You can do checks using lookarounds:
^(?=.*\bjack\b)(?=.*\bjames\b).*$
Test it.
This approach has the advantage that you can easily specify multiple conditions.
^(?=.*\bjack\b)(?=.*\bjames\b)(?=.*\bjason\b)(?=.*\bjules\b).*$
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,}
You can do:
\bjack\b.*\bjames\b|\bjames\b.*\bjack\b