How can I "inverse match" with regex?

Viewed 354222

I'm processing a file, line-by-line, and I'd like to do an inverse match. For instance, I want to match lines where there is a string of six letters, but only if these six letters are not 'Andrea'. How should I do that?

I'm using RegexBuddy, but still having trouble.

10 Answers
(?!Andrea).{6}

Assuming your regexp engine supports negative lookaheads...

...or maybe you'd prefer to use [A-Za-z]{6} in place of .{6}

Note that lookaheads and lookbehinds are generally not the right way to "inverse" a regular expression match. Regexps aren't really set up for doing negative matching; they leave that to whatever language you are using them with.

The capabilities and syntax of the regex implementation matter.

You could use look-ahead. Using Python as an example,

import re

not_andrea = re.compile('(?!Andrea)\w{6}', re.IGNORECASE)

To break that down:

(?!Andrea) means 'match if the next 6 characters are not "Andrea"'; if so then

\w means a "word character" - alphanumeric characters. This is equivalent to the class [a-zA-Z0-9_]

\w{6} means exactly six word characters.

re.IGNORECASE means that you will exclude "Andrea", "andrea", "ANDREA" ...

Another way is to use your program logic - use all lines not matching Andrea and put them through a second regex to check for six characters. Or first check for at least six word characters, and then check that it does not match Andrea.

Negative lookahead assertion

(?!Andrea)

This is not exactly an inverted match, but it's the best you can directly do with regex. Not all platforms support them though.

If you want to do this in RegexBuddy, there are two ways to get a list of all lines not matching a regex.

On the toolbar on the Test panel, set the test scope to "Line by line". When you do that, an item List All Lines without Matches will appear under the List All button on the same toolbar. (If you don't see the List All button, click the Match button in the main toolbar.)

On the GREP panel, you can turn on the "line-based" and the "invert results" checkboxes to get a list of non-matching lines in the files you're grepping through.

If you have the possibility to do two regex matches for the inverse and join them together you can use two capturing groups to first capture everything before your regex

^((?!yourRegex).)*

and then capture everything behind your regex

(?<=yourRegex).*

This works for most regexes. One problem I discovered was when I had a quantifier like {2,4} at the end. Then you gotta get creative.

In Perl you can do:

process($line) if ($line =~ !/Andrea/);
Related