4

I want to match strings that don't have abc, def or ghi. The opposite is easy:

/(abc|def|ghi)/

How do I reverse that? I don't want to

/(^abc|^def|^ghi)/

because there's going to be more 'logic' in there. (If that's even what it does.)

How do I reverse the whole group match (or whatever it's called)?

(I'm trying to beat 5. on http://regex.alf.nu/)

Rudie
  • 52,220
  • 42
  • 131
  • 173

4 Answers4

9

Use negative lookaead:

/^(?!.*?(abc|def|ghi)).*$/
anubhava
  • 761,203
  • 64
  • 569
  • 643
  • That's going to look a bit goofy in practice: that'll match (positively) `bobabc`. – brandonscript Dec 20 '13 at 19:01
  • Why the string start/end and word boundaries? – Rudie Dec 20 '13 at 19:24
  • The `^` was apparently necessary. Not the `$`. The `\b` actually broke it. Has to not-match anywhere. Now it works: `^(?!.*?(.)\1\1)` (the non-match were actually `aaa|bbb|ccc` etc). Negative lookaround is hard. – Rudie Dec 20 '13 at 19:37
3

You need to define the capture group including the start (^) and end of the string ($), or you'll end up with false positive matches:

/^((?!(abc|def|ghi)).)*$/

This will match:

  • bob
  • joe

This will not match:

  • abc
  • def
  • ghi
  • bobabc
  • abcjoe

See it in action here: http://regex101.com/r/yI3tF4

brandonscript
  • 68,675
  • 32
  • 163
  • 220
  • I don't get it... Why the start/end? How does the lookahead affect the `.` after it? Maybe I just don't get neg/pos lookahead/behind.... – Rudie Dec 20 '13 at 19:30
  • Well, the start/end are there because you want to make sure the entire string doesn't match what you're negating. In this case, you're iterating through every character to make sure it's not followed by your match condition. tl;dr: lookarounds are REALLY confusing, best just to use them and not understand them I always say ^_^ Regex101 does provide a pretty good explanation though. – brandonscript Dec 20 '13 at 19:36
  • Confusing. Yes! Your regex doesn't work though. And I've no idea how it works, so I can't fix it. It seems to me that the `.` should be before the lookahead though, to match all chars without that look ahead. I'm trying 5. on http://regex.alf.nu/ I got all the rest. – Rudie Dec 20 '13 at 19:40
  • @Rudie hm, then it's probably not using the javascript engine. Try just `\b((?!(abc|def|ghi)).)*\b` ? – brandonscript Dec 20 '13 at 19:42
  • Also the . can't go before unless you write in multiple non-greedy possibilities of it, like `^(?!.*?(abc|def|ghi)).+$` or something., because of the way javascript orders the check; it's convoluted, but that's just the way it's done. – brandonscript Dec 20 '13 at 19:43
3

Solution to 5. on http://regex.alf.nu/ : ^((?!(.)(.)\3\2).)*$
Explanation : Regular expression to match a line that doesn't contain a word?

Community
  • 1
  • 1
bits
  • 1,595
  • 1
  • 17
  • 17
  • Yes, that question! I don't understand your regex at all though... I tried `^(?!.*?(.)\1)` but that doesn't match "e_ff_usive" or "noisefu_ll_y". How does yours work?? – Rudie Dec 21 '13 at 11:39
0

Using negative lookaheads :

/^(?!.*abc)(?!.*def)(?!.*ghi)/
/^(?!.*(abc|def|ghi))/