How to combine negative lookbehind and negative lookahead

Viewed 56

Combine negative lookbehind and negative lookahead

How can I combine negative lookbehind (?<!) and negative lookahead (?!) with an AND?

With .Net/C#

I want to find the word big, but only if it is not inside (or [ or ` AND ) or ] or `
The problem is that I can't find big either when one of the brackets is there

Demo

https://regex101.com/r/V78jxd/2

Regex

(?<![\(\[`])big(?!.*[\)\]`])

Test Data

Should Match: 
I like `xx` big `xx` cakes

I like big cakes
I like `big cakes
I like big` cakes
I like xx big xx cakes
I like ` xx big xx cakes
I like xx big xx` cakes
I like `xx` big `xx` cakes

I like big cakes
I like [big cakes
I like big] cakes
I like xx big xx cakes
I like [ xx big xx cakes
I like xx big xx] cakes
I like [xx] big [xx] cakes

I like big cakes
I like (big cakes
I like big) cakes
I like xx big xx cakes
I like ( xx big xx cakes
I like xx big xx) cakes
I like (xx) big (xx) cakes
                                               
I like (xx(test(big test big ( big ))) big xx) big  (xx(test(big test big ( big ))) big xx) cakes
                                               ^^^

Should not Match: 
I like (big) cakes
I like (xx big xx) cakes
I like [big] cakes
I like [xx big xx] cakes
I like `big` cakes
I like `xx big xx` cakes
I like (xx(test(big test big ( big ))) big xx) cakes
2 Answers

Since .NET regex allows variable-width lookbehind patterns you can use

(?<!\((?=[^()\n]*\))[^()\n]*)big

See the regex demo.

Note the \ns are only necessary when you need to match on a per-line basis. Remove all \ns when you need the pattern to work with standalone texts.

Details:

  • (?<!\((?=[^()\n]*\))[^()\n]*) - a negative lookbehind that fails the match if there is a ( char and then zero or more chars other than parentheses and a newline immediately on the left, that is not immediately followed with any zero or more chars other than parentheses and a newline and then a ) char
  • big - big char sequence.

If you want to take balanced parenthesis into account, you can use match those using balancing groups and then use an alternation | and capture the word \b(big)\b in capture group 1.

\((?>\((?<open>)|[^\r\n()]+|\)(?<-open>))*(?(open)(?!))\)|\b(big)\b

See a .NET regex demo.

Related