Srb1313711
Srb1313711

Reputation: 2047

Match anything that is a something?

With regex how can a match everything in a string that isnt something? This may not make sense but read on.

So take the word baby for instance to match everything that isn't a b you would do something like [^b] and this would match a and y. Simple enough! But how in this string Ben sits on a bench can I match everything that isn't ben so i would be attempting to match sits on a ch?

Better yet match everything that isn't a pattern? e.g. in 1a2be3 match everything that isn't number,letter,number, so it would match every combination in the string except 1a2?

Upvotes: 8

Views: 532

Answers (6)

Adam Katz
Adam Katz

Reputation: 16118

Short answer: You can't do what you're asking. Technically, the first part has an ugly answer, but the second part (as I understand it) has no answer.


For your first part, I have a pretty impractical (yet pure regex) answer; anything better would require code (like @rednaw's much cleaner answer above). I added to the test to make it more comprehensive. (For simplicity, I'm using grep -Pio for PCRE, case insensitive, printing one match per line.)

$ echo "Ben sits on a bench better end" \
    |grep -Pio '(?=b(?!en)|(?<!b)en|e(?!n)|(?<!be)n|[^ben])\w+'
sits
on
a
ch
better
end

I'm basically making a special case for any letter in "ben" so I can include only iterations that are not themselves part of the string "ben." As I said, not really practical, even if I am technically answering your question. I've also saved a blow-by-blow explanation of this regex if you want further detail.

If you're forced into using a pure regex rather than code, your best bet for items like this is to write code to generate the regex. That way you can keep a clean copy of it.


I'm not sure what you're asking for the remainder of your challenge; a regex is either greedy or lazy [1] [2], and I don't know of any implementations that can find "every combination" rather than merely the first combination by either method. If there were such a thing, it would be very very slow in real life (rather than quick examples); the slow speed of regex engines would be intolerable if they were forced to examine every possibility, which would basically be a ReDoS.

Examples:

# greedy evaluation (default)
$ echo 1a2be3 |grep -Pio '(?!\d[a-z]\d)\w+'
a2be3

# lazy evaluation
$ echo 1a2be3 |grep -Pio '(?!\d[a-z]\d)\w+?'
a
2
b
e
3

I assume you are looking for 1 1a a a2 a2b a2be a2be3 2 2b 2be 2be3 b be be3 e e3 3 but I don't think you can get that with a pure regex. You'd need some code to generate every substring and then you could use a regex to filter out the forbidden pattern (again, this is all about greedy vs lazy vs ReDoS).

Upvotes: 1

Yuri  Kovalev
Yuri Kovalev

Reputation: 659

If you want list of strings, use "split on regexp" instead of "match on regexp".

Upvotes: 0

Bohemian
Bohemian

Reputation: 424983

Just replace everything that matches your pattern with a blank (to delete it).

You haven't indicated what language you are using, so genetically:

s/ben//g

and your other example:

s/\d[a-zA-Z]\d//g

Upvotes: 0

Ronin
Ronin

Reputation: 33

Okay The simplest thing To Do is Match Everything

(.*?)

Then on the pattern matched do another Match for What you don't want(for e.g In perl you will have the pattern matched in the variable $&).

If it matches, That's not what you want else you have your match.

Simple A-B where A is everything(.*?) and B is What you don't want.So you end up doing two matches but i think that's fine.

Upvotes: 0

gitaarik
gitaarik

Reputation: 46280

(?:ben)|(.)

What this regex does is match ben or any other character, however, ben isn't captured but the other characters are. So you'll end up with a lot of matches except for the ben's. Then you can join all those matches together to get the string without the ben's.

Here an example in python.

import re

thestr = "Ben sits on a bench"
regex = r'(?:ben)|(.)'

matches = re.findall(regex, thestr, re.IGNORECASE)
print ''.join(matches)

This will ouput:

 sits on a ch

Note the leading space. You can of course get rid of that by adding .strip().

Also note, that it is probably faster to do a regex that replaces ben with an empty string to get the same result. But if you want to use this technique in a more complex regex it could come in handy.

And of course you can also put more complex regexes at the place of ben, so for example your number,letter,number example would be:

(?:[0-9][a-z][0-9])|(.)

Upvotes: 1

hillel
hillel

Reputation: 2373

If you want to match all the words except one, you can use negative lookahead: \b(?!ben\b)\w*\b, but for an answer to your exact question Jon's comment seems the simplest.

Upvotes: 0

Related Questions