I know that I can negate group of chars as in [^bar]
but I need a regular expression where negation applies to the specific word - so in my example how do I negate an actual bar
, and not "any chars in bar"?
-
Related: [regex for matching something if it is not preceded by something else](https://stackoverflow.com/q/9306202/3258851) – Marc.2377 Oct 24 '19 at 07:29
12 Answers
A great way to do this is to use negative lookahead:
^(?!.*bar).*$
The negative lookahead construct is the pair of parentheses, with the opening parenthesis followed by a question mark and an exclamation point. Inside the lookahead [is any regex pattern].

- 12,019
- 6
- 66
- 69

- 36,423
- 9
- 73
- 90
-
23This says it all (I probably would have started with (?!bar) and built up). I don't see why other people are making it so complicated. – Beta Aug 07 '09 at 14:49
-
6
-
I don't think light weight regex parsers like SLRE support ! operator yet. – enthusiasticgeek Feb 28 '14 at 12:49
-
3Nicely done - matches a line that has the specified string and the string is not preceded by anything and the string is followed by anything.This is by definition the absence of the string! because if present it will always be preceded by something even if its a line anchor ^ – Pete_ch Nov 13 '14 at 15:35
-
Is there a version of this that works in the Linux command line `grep` utility? – Neil Traft Sep 27 '15 at 02:03
-
3
-
2If you are using grep then use -P option. -P enables perl regex. e.g. grep -P '(?!do not contain this string)' – seenimurugan Sep 21 '16 at 13:32
-
this worked "just right" with the extra info provided by @sgrillon's answer – RozzA Oct 30 '16 at 18:36
-
I want not allow to user to write "Password", "password" or any other exact word. – Irfan Nasim Mar 31 '17 at 06:15
-
2Unfortunately, this doesn't works with actual words. `foo` will match, `bar` won't, but `foobar` or `barfoo` won't too! – bzim Jun 30 '17 at 21:01
-
-
@bzim That is correct and expected as those other three contain the "bar" so they shouldn't match. Foo is the only word of those three you gave that doesn't have the "bar" – carinlynchin Dec 18 '19 at 20:56
-
1this is exactly what i needed .. but I'm curious why doesn't `^(?!bar).*$` work? It's technically saying if it doesn't contain 'bar' right? why does it require the .* I have checked and it actually doesn't, can anyone explain or break it down for me. – carinlynchin Dec 18 '19 at 21:01
-
-
@carilynchin its because `^` also applies within the lookahead. So you are saying you want all strings that don't start with `bar`. This means you will match all strings without bar AND all strings which have bar EXCEPT those that START with `bar`. That's not desired by OP. – Ben Butterworth Oct 09 '20 at 17:55
-
-
Instead, I read `^(?!.*bar).*$` as "Match any string--it must NOT start with "any characters followed by 'bar'" --but it can have any other set of characters". The "must NOT start with ..." bit is `^(?!.*bar)`. The "can have any other..." bit is the final '.*$' – Happyblue Aug 06 '21 at 11:35
-
Thinking about my text explanation above, I do not see a need for the final `$` at the end - I think it can be dropped. So a slightly improved regex should be `^(?!.*bar).*`. Can a regex guru validate this and update the answer please? – Happyblue Aug 06 '21 at 11:43
Unless performance is of utmost concern, it's often easier just to run your results through a second pass, skipping those that match the words you want to negate.
Regular expressions usually mean you're doing scripting or some sort of low-performance task anyway, so find a solution that is easy to read, easy to understand and easy to maintain.

- 370,779
- 53
- 539
- 685
-
38There are lots of situations where you don't control the workflow: you just get to write a single regexp which is a filter. – Steve Bennett Mar 22 '18 at 04:08
-
1And if you want to replace all Texts which don't match a certain regex? – user unknown Nov 08 '19 at 19:10
-
It special idea, but it does work. Most of the answers are for [PCRE](https://en.wikipedia.org/wiki/Perl_Compatible_Regular_Expressions), but It can't apply their solution to [re2](https://github.com/google/re2/wiki/Syntax) – Carson Apr 22 '21 at 06:49
Solution:
^(?!.*STRING1|.*STRING2|.*STRING3).*$
xxxxxx OK
xxxSTRING1xxx KO (is whether it is desired)
xxxSTRING2xxx KO (is whether it is desired)
xxxSTRING3xxx KO (is whether it is desired)

- 11,140
- 10
- 85
- 154
-
7
-
5Am I the only one who hates "OK" and "KO" as indicators of passing a test? It's just one typo away from disaster... – AJPerez Dec 13 '21 at 07:32
You could either use a negative look-ahead or look-behind:
^(?!.*?bar).*
^(.(?<!bar))*?$
Or use just basics:
^(?:[^b]+|b(?:$|[^a]|a(?:$|[^r])))*$
These all match anything that does not contain bar
.

- 643,351
- 109
- 780
- 844
-
What languages don't support (negative) look-behinds and/or (negative) look-aheads in regex? – JAB Aug 06 '09 at 17:29
-
6I think the point being made is, looking at your pattern it's not at all clear that all you're doing is rejecting the word "bar". – Bryan Oakley Aug 06 '09 at 17:34
-
@Bryan: And, in fact, it doesn't reject the word "bar". It just rejects "b" when followed by "ar". – JAB Aug 06 '09 at 18:05
-
Good idea, but not supported everywhere. Afaik Javascript supports negative look-ahead, but not look-behind. I don't know details about other languages, but this can be helpful: https://en.wikipedia.org/wiki/Comparison_of_regular_expression_engines – mik01aj Jul 08 '15 at 07:58
-
-
-
Can you explain the second solution? `(.(?<!bar))*?` `(?<!bar)` is a negative lookbehind, isn't it? It follows the pattern `(?<!a)b`, that would mean: wherever you find a `b`, make sure there isn't an `a` before it. Only that in this case, `b` is empty for us; so it would mean: wherever you find anything, make sure there isn't a `bar` before it. But how does it work the `(.
)*?`? Why do you need the `.` and the last `?` there? Many thanks! – rturrado May 21 '19 at 10:22 -
` ^(?!.*?bar).* ` Why did you use lazy here ? Why does just `^(?!bar).*` not work ? – adiaux Feb 06 '23 at 11:16
The following regex will do what you want (as long as negative lookbehinds and lookaheads are supported), matching things properly; the only problem is that it matches individual characters (i.e. each match is a single character rather than all characters between two consecutive "bar"s), possibly resulting in a potential for high overhead if you're working with very long strings.
b(?!ar)|(?<!b)a|a(?!r)|(?<!ba)r|[^bar]

- 20,783
- 6
- 71
- 80
-
7Instead of those multiple updates which force us to read the wrong answers before getting to your final answer, why not rewrite your answer to be complete, but without the somewhat confusing bad parts? If somebody really cares about the edit history they can use the built-in features of this site. – Bryan Oakley Jun 19 '12 at 13:12
-
17
-
3
-
@Mary, This won't work as expected. For example `/(?:(?!bar).)*/g` on `foobar` returns `foo` AND `ar`. – Krzysiek Jan 07 '15 at 16:08
I came across this forum thread while trying to identify a regex for the following English statement:
Given an input string, match everything unless this input string is exactly 'bar'; for example I want to match 'barrier' and 'disbar' as well as 'foo'.
Here's the regex I came up with
^(bar.+|(?!bar).*)$
My English translation of the regex is "match the string if it starts with 'bar' and it has at least one other character, or if the string does not start with 'bar'.

- 73,866
- 12
- 100
- 156

- 361
- 3
- 3
-
@ReReqest - you will have much better chance to have this question answered if you post it as a separate question. In that you can provide link back to this question if you want. For the substance of question - it looks OK but I'm no regex guru – Bostone Sep 11 '10 at 17:47
-
2That was the one I was looking for. It really matches everything except bar. – Gabriel Hautclocq Dec 17 '15 at 20:34
-
4`^(?!bar$).*` matches the same as this (everything except exactly `bar`) and avoids repetition. – bkDJ Jun 06 '18 at 13:17
The accepted answer is nice but is really a work-around for the lack of a simple sub-expression negation operator in regexes. This is why grep --invert-match
exits. So in *nixes, you can accomplish the desired result using pipes and a second regex.
grep 'something I want' | grep --invert-match 'but not these ones'
Still a workaround, but maybe easier to remember.

- 2,032
- 1
- 18
- 18
-
1This is the right answer for someone using grep, which certainly qualifies as regex. I just wish this answer were more prominent (even included in the accepted answer) so that I hadn't spent time with the other answers first. – user2225804 Dec 31 '19 at 14:12
-
I cant see the `invert match` option in R. Is it restricted to unix grep? – Lazarus Thurston Oct 06 '20 at 17:02
-
I use a GUI-based grep like [TextCrawler](https://www.digitalvolcano.co.uk/textcrawler.html). But if you are not using Windows OS, not sure what to use. – Jon Grah Aug 05 '22 at 05:35
Extracted from this comment by bkDJ:
^(?!bar$).*
The nice property of this solution is that it's possible to clearly negate (exclude) multiple words:
^(?!bar$|foo$|banana$).*

- 14,760
- 11
- 69
- 98
-
9
-
1
-
Seems to work by extracting the `$`, too: `^(?!(bar|foo|banana)$).*` :-) – Glenn Mohammad Jul 18 '22 at 11:32
If it's truly a word, bar
that you don't want to match, then:
^(?!.*\bbar\b).*$
The above will match any string that does not contain bar
that is on a word boundary, that is to say, separated from non-word characters. However, the period/dot (.
) used in the above pattern will not match newline characters unless the correct regex flag is used:
^(?s)(?!.*\bbar\b).*$
Alternatively:
^(?!.*\bbar\b)[\s\S]*$
Instead of using any special flag, we are looking for any character that is either white space or non-white space. That should cover every character.
But what if we would like to match words that might contain bar
, but just not the specific word bar
?
(?!\bbar\b)\b\[A-Za-z-]*bar[a-z-]*\b
(?!\bbar\b)
Assert that the next input is notbar
on a word boundary.\b\[A-Za-z-]*bar[a-z-]*\b
Matches any word on a word boundary that containsbar
.

- 38,656
- 3
- 37
- 60
I wish to complement the accepted answer and contribute to the discussion with my late answer.
@ChrisVanOpstal shared this regex tutorial which is a great resource for learning regex.
However, it was really time consuming to read through.
I made a cheatsheet for mnemonic convenience.
This reference is based on the braces []
, ()
, and {}
leading each class, and I find it easy to recall.
Regex = {
'single_character': ['[]', '.', {'negate':'^'}],
'capturing_group' : ['()', '|', '\\', 'backreferences and named group'],
'repetition' : ['{}', '*', '+', '?', 'greedy v.s. lazy'],
'anchor' : ['^', '\b', '$'],
'non_printable' : ['\n', '\t', '\r', '\f', '\v'],
'shorthand' : ['\d', '\w', '\s'],
}

- 3,289
- 1
- 15
- 22

- 19,953
- 19
- 81
- 138
Just thought of something else that could be done. It's very different from my first answer, as it doesn't use regular expressions, so I decided to make a second answer post.
Use your language of choice's split()
method equivalent on the string with the word to negate as the argument for what to split on. An example using Python:
>>> text = 'barbarasdbarbar 1234egb ar bar32 sdfbaraadf'
>>> text.split('bar')
['', '', 'asd', '', ' 1234egb ar ', '32 sdf', 'aadf']
The nice thing about doing it this way, in Python at least (I don't remember if the functionality would be the same in, say, Visual Basic or Java), is that it lets you know indirectly when "bar" was repeated in the string due to the fact that the empty strings between "bar"s are included in the list of results (though the empty string at the beginning is due to there being a "bar" at the beginning of the string). If you don't want that, you can simply remove the empty strings from the list.

- 20,783
- 6
- 71
- 80
-
2@Ajk_P yes but this kind of answers may help the OP think outside the box, they could've been fixated on regexes not realizing that it could be solved without them. – Petruza Jul 21 '17 at 15:53
I had a list of file names, and I wanted to exclude certain ones, with this sort of behavior (Ruby):
files = [
'mydir/states.rb', # don't match these
'countries.rb',
'mydir/states_bkp.rb', # match these
'mydir/city_states.rb'
]
excluded = ['states', 'countries']
# set my_rgx here
result = WankyAPI.filter(files, my_rgx) # I didn't write WankyAPI...
assert result == ['mydir/city_states.rb', 'mydir/states_bkp.rb']
Here's my solution:
excluded_rgx = excluded.map{|e| e+'\.'}.join('|')
my_rgx = /(^|\/)((?!#{excluded_rgx})[^\.\/]*)\.rb$/
My assumptions for this application:
- The string to be excluded is at the beginning of the input, or immediately following a slash.
- The permitted strings end with
.rb
. - Permitted filenames don't have a
.
character before the.rb
.

- 2,194
- 20
- 23