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
4
  • @WiktorStribiżew what is duplicate about this? Commented Feb 11, 2016 at 13:11
  • 1
    Your regex (/(?=best)(?=life)/) say find a NOTHING that there is 'best life' before that ! Commented Feb 11, 2016 at 13:12
  • what do you really want to achieve ? Commented Feb 11, 2016 at 13:13
  • @nAviD if the string contains best + life, it should be true. Commented Feb 11, 2016 at 13:16

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

2 Comments

@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).
And it is good you do not have /g, because you should not use /g with RegExp#test()

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.