RegEx: Find pattern but exclude words

Viewed 1221

I want to find all connected words except for specific ones. For example:

0827banana82/+wine22green-729

green and wine should match, but banana not.

I tried the following regular expression with a negative lookahead:

(?!banana)([a-zA-Z]+)

but it excludes only the first letter of banana because anana is still a match for the second pattern. I have no idea how to get rid of that.

6 Answers

You may add a negative lookbehind in your regex to make it work:

(?!banana)(?<![a-zA-Z])[a-zA-Z]+

RegEx Demo

RegEx Details:

  • (?!banana): Negative lookahead to assert that we don't have string banana ahead of the current position
  • (?<![a-zA-Z]): Negative lookbehind to assert that we don't have a letter before current position
  • [a-zA-Z]+: Match 1+ letters

PS: If you want to allow words like bananas then use:

(?!banana(?![a-zA-Z]))(?<![a-zA-Z])[a-zA-Z]+

Well you can use this one:

(banana)|([a-zA-Z]+)

Which will capture banana in 1st group and all the other words in 2nd.

My two cents, assuming you do want to match words like "bananas":

(\b|\d)(?:banana|([a-zA-Z]+))(?1)

Your matches are in group 2, see an online demo

  • (\b|\d) - A 1st capture group to hold a word-boundary or a digit.
  • (?:banana|([a-zA-Z]+)) - A non-capture group with the alternation of either exactly "banana" or a 2nd capture group of 1+ alpha-chars.
  • (?1) - Repeat the subpattern of the 1st capture group.

EDIT: If the backreference is not supported, you can try

(?:\b|\d)(?:banana|([a-zA-Z]+))(?:\b|\d)

Or, using lookarounds:

(?i)(?<![a-z])(?:banana|([a-z]+))(?![a-z])

Another variation might be matching the characters a-zA-Z until there are no more. Then assert that banana is not directly to the left.

[a-zA-Z]+(?![a-zA-Z])(?<!banana)

The pattern matches

  • [a-zA-Z]+ Match 1+ chars a-zA-Z
  • (?![a-zA-Z]) Negative lookahead, assert not a-zA-Z directly to the right
  • (?<!banana) Negative lookbehind, assert banana not directly to the left

Regex demo


If you want to match bananas or straigtbanana you can assert that on the left is not banana preceded by a char a-zA-Z

[a-zA-Z]+(?![a-zA-Z])(?<!(?<![a-zA-Z])banana)

Regex demo


As suggested by @bobble bubble in the comments, if possessive quantifiers are supported and shortening the pattern using a case insensitive match:

[a-z]++(?<!(?<![a-z])banana)
  • [a-z]++ Match 1+ chars in the range of a-z (possessive, do not backtrack)
  • (?<! Negative lookbehind, assert what is directly to the left is not
    • (?<![a-z])banana Negative lookbehind, match banana not preceded by a-z
  • ) Close lookbedhind

Regex demo

Use the below regex to avoid one single word.

(?![banana])([a-zA-Z]+)
/\b(((?!banana|apple|[^\p{L}]).)+)\b/gu

You need to use the word boundary \b expression \b. Banana apple will be excluded from your match.

At the end use gui if you want to exclude Banana and Apple too (capitalized text including upper case).

\p{L} will match any word including diacritics.

If you need just banana to be excluded delete |apple. If you need to add more like orange after apple add |orange.

Related