33

I'm not terribly certain what the correct wording for this type of regex would be, but basically what I'm trying to do is match any string that starts with "/" but is not followed by "bob/", as an example.

So these would match:

/tom/
/tim/
/steve

But these would not

tom
tim
/bob/

I'm sure the answer is terribly simple, but I had a difficult time searching for "regex not" anywhere. I'm sure there is a fancier word for what I want that would pull good results, but I'm not sure what it would be.

Edit: I've changed the title to indicate the correct name for what I was looking for

tchrist
  • 78,834
  • 30
  • 123
  • 180
GoldenNewby
  • 4,382
  • 8
  • 33
  • 44

2 Answers2

35

You can use a negative lookahead (documented under "Extended Patterns" in perlre):

/^\/(?!bob\/)/
brian d foy
  • 129,424
  • 31
  • 207
  • 592
  • Probably /^\/(?!bob\/)/ , though-- but you got the gist of it. Thanks! – GoldenNewby Apr 04 '12 at 00:25
  • @GoldenNewby Woops, overlooked that part of the question –  Apr 04 '12 at 00:25
  • 2
    With default regex flags now a feature, that `^` is better written as `\A`. With alternate delimiters and `/x`, it looks like `m| \A / (?!bob/) |x`. – brian d foy Apr 04 '12 at 03:41
  • 9
    @brian d foy, It's preposterous to suggest the existence this feature means `/^/` has to be changed to `/\A/`, `/$/` to `/(?=\n?\z)/`, `/./` to `/[^\n]/` and `/ /` to `/[ ]/`. – ikegami Apr 04 '12 at 07:45
  • @ikegami: `$` should be `\z` more often than not anyway; I am not without appreciation for a reason to use the parallel `\A` – ysth Apr 05 '12 at 05:05
8

TLDR: Negative Lookaheads

If you wanted a negative lookahead just to find "foo" when it isn't followed by "bar"...

$string =~ m/foo(?!bar)/g;

Working Demo Online

Source

To quote the docs...

(?!pattern)

(*nla:pattern)

#(*negative_lookahead:pattern)

A zero-width negative lookahead assertion. For example /foo(?!bar)/ matches any occurrence of "foo" that isn't followed by "bar". Note however that lookahead and lookbehind are NOT the same thing. You cannot use this for lookbehind. (Source: PerlDocs.)

Negative Lookaheads For Your Case

The accepted answer is great, but it leaves no explanation, so let me add one...

/^\/(?!bob\/)/
  • ^ — Match only the start of strings.
  • \/ — Match the / char, which we need to escape because it is a character in the regex format (i.e. s/find/replacewith/, etc.).
  • (?!...) — Do not match if the match is followed by ....
  • bob\/ — This is the ... value, don't match bob/', once more, we need to escape the /`.
HoldOffHunger
  • 18,769
  • 10
  • 104
  • 133