Search code examples
regexregex-lookaroundsregex-group

Regex Negative Lookahead Is Being Ignored


I have the following sample text

[Item 1](./path/notes.md)
[Item 2](./path)
[Item 3](./path/notes.md)
[Item 4](./path)

When I applied the following regex \[(.*)\].*(?!notes\.md).*\), I expected the following output when I printed the first capture group

Item 2
Item 4

but what I ended up getting was

Item 1
Item 2
Item 3
Item 4

which, to me, seems that the negative lookahead portion, (?!notes\.md), was being ignored for some reason, so the regex was matching the whole string.

What is really confusing me, is that a positive lookahead works as I would expect. For example using \[(.*)\].*(?=notes\.md).*\) returns the following when printing the first capture group

Item 1
Item 3

which makes sense, so I am really confused as to why the negative lookahead is not functioning properly.


Solution

  • Let's go through what happens when matching your pattern on item 1:

    • \[(.*)\] matches [Item 1]
    • .* matches (./path/notes.md
    • The remaining string is now )
    • (?!notes\.md) checks whether the remaining string matches the pattern notes\.md. It does not, so the match continues.
    • \) matches the ) and the match succeeds.

    If you change it so that the .* before the lookahead is inside the lookahead instead (\[(.*)\](?!.*notes\.md).*\)), it will now work as follows:

    • \[(.*)\] matches [Item 1]
    • The remaining string is now (./path/notes.md)
    • (?!.*notes\.md) checks whether the remaining string matches the pattern .*notes\.md, which it does, so the match fails (well more precisely, the regex engine will try to backtrack before it gives up on the match, but there's no alternative way to match \[(.*)\]', so the match still fails).

    So with that change, it will reject all strings where notes.md appears anywhere before the ). If you want it to only reject instances where notes.md appears directly before the ), you can use a loookbehind (without .*) instead or add the \) to the lookahead.