0

I'm trying to understand why this is returning false, and what I can do to make it true.

var str = "The best things in life are free";
var patt = new RegExp(/(?=best)(?=life)/i);
var res = patt.test(str); // = false. But expect true because both 'best' and 'life' are in the string
Bob van Luijt
  • 7,153
  • 12
  • 58
  • 101

1 Answers1

1

The problem is that your lookaheads require best and life be at the same position in the string. Look-aheads are zero-width assertions and do not advance the RegExp index. Thus, your /(?=best)(?=life)/i checks at each position (if you move the lastIndex manually in the code) if the location is followed with best and life.

Use

/^(?=.*best)(?=.*life)/i

This regex will require best and life to be present at any location inside the string.

var str = "The best things in life are free";
var patt = /^(?=.*best)(?=.*life)/i;
var res = patt.test(str);
document.body.innerHTML = res;

Why /^(?=.*best)(?=.*life)/i but not /(?=.*best)(?=.*life)/i?

When not anchored, lookaheads are executed at each position. When we set the ^ in the beginning, the two lookaheads are executed one after another (if the previous one succeeded). Performance is much better when you only execute them once. In this case,however, there is no difference because there is no /g modifier in the regular expression.

Why not /best.*life|life.*best/?

You can, it will require an alternation, and in case you have a lot of such alternatives, it will be more difficult to maintain.

Why not use .indexOf?

Because the next possible enhancement is matching the two words as whole words:

/^(?=.*\bbest\b)(?=.*\blife\b)/i

So as not to match bestie or afterlife.

And the last, but not least note: if your string can contain a newline, replace the .* with [\s\S]* since a dot in a JS regex cannot match a newline.

Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
  • 1
    @BobvanLuijt: You do not have `/g` modifier, thus both `/(?=.*best)(?=.*life)/i` and `/^(?=.*best)(?=.*life)/i` should work the same (since string is processed from left to right). – Wiktor Stribiżew Feb 11 '16 at 13:28
  • And it is good you do not have `/g`, because you [should not use `/g` with `RegExp#test()`](http://stackoverflow.com/questions/1520800/why-regexp-with-global-flag-in-javascript-give-wrong-results) – Wiktor Stribiżew Feb 11 '16 at 14:01