Why doesn't negative lookahead prevent matching if followed by what's in its group?

Viewed 80

I have the following RegExp: (?<= )L.*(?!MH$).

The idea is:

  • (?<= ) 4 spaces must precede the match, but not be included in the match.
  • L.* The match must begin with L and include the rest of the string ...
  • (?!MH$) UNLESS MH is at the end of the string.

This last condition is being ignored. The string ending with MH still matches. Why?

const regExpStr = String.raw`(?<=    )L.*(?!MH$)`;
const regExp = new RegExp(regExpStr);
const str = '2.    L2 B4 RHODA 1 ADDN,SOMECITY,OK,74999 - 81 HILLCREST MH';
const match = str.match(regExp)?.[0];

console.log(match);

2 Answers

You may use this regex with an extra negative lookbehind in the end:

(?<= {4})L.*$(?<!MH)

RegEx Demo

RegEx Details:

  • (?<= {4}): Allow this match when we have 4 spaces before current position
  • L.*$: Match a string starting with L till end
  • (?<!MH): Fail the match when we have MH before current position (end)

The last condition of your pattern is being ignored because the pattern first asserts 4 spaces to the left, then matches L followed by matching any char except a newline till the end of the string.

Then, at the end of the string, the pattern asserts what is directly to the right is not MH. That assertion is true because it is at the end of the string, so MH can not be at the right.

You could update your pattern to match L and directly after it, assert using a quantifier .* that at the end of the string there is not MH.

(?<= {4})L(?!.*MH$).*

Regex demo

Related