Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Match anything that is a something?

Tags:

regex

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?

like image 435
Srb1313711 Avatar asked Dec 10 '13 10:12

Srb1313711


People also ask

What is the regex for anything?

(wildcard character) match anything, including line breaks. Throw in an * (asterisk), and it will match everything. Read more. \s (whitespace metacharacter) will match any whitespace character (space; tab; line break; ...), and \S (opposite of \s ) will match anything that is not a whitespace character.

What is ?! In regex?

Definition and Usage. The ?! n quantifier matches any string that is not followed by a specific string n.

Which pattern matches any character other than a number?

The uppercase counterpart \D (non-digit) matches any single character that is not a digit (same as [^0-9] ). \s (space) matches any single whitespace (same as [ \t\n\r\f] , blank, tab, newline, carriage-return and form-feed).

What regex matches any character?

By default, the '. ' dot character in a regular expression matches a single character without regard to what character it is. The matched character can be an alphabet, a number or, any special character.


2 Answers

(?: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])|(.)
like image 74
gitaarik Avatar answered Oct 23 '22 06:10

gitaarik


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).

like image 36
Adam Katz Avatar answered Oct 23 '22 04:10

Adam Katz