Regex capturing block of condition

Viewed 67

I have the following string

huile contains rgbgrbrb9gr && huile contains fcecec

I use this regex in order to capture a block of condition:

(.+) (contains) (.+)

It works with one block "huile contains rgbgrrb9gr" but if i add another condition with && or || operator, the two operators are captured. What i'm expecting to capture if the two blocks excluding && and || operator.

Can someone have any idea how to achieve this?

3 Answers

Regex normally matches the longest input it finds.

You need to exclude & and | from your input, like this:

([^&|]+) (contains) ([^&|]+)

If you instead desire to exclude double-character && and ||, I suggest spliting your string based on those delimiters first, then matching using regex, as complex parsing is really beyond the realm of regex (they're grammars actually).

But, a regex solution is nontheless possible

The rough idea is that, you want to match a string with

  1. an optional prefix consisting of no & or |
  2. a single & or | followed by a non-empting string
  3. repeating 2 for non-zero number of times.

the subpattern would be something like this:

(([^&|]+)?([&|][^&|]+)+)

additionally, you'll want something like the egrep's x flag, to match the entire string, otherwise it'll be possible that an empty string turns up.

The full regex would look something like this (capture groups're re-numbered)

(([^&|]+)?([&|][^&|]+)+) (contains) (([^&|]+)?([&|][^&|]+)+)

After reading the post comments, the desired result was more clear.

This one could work too:

(?<=^|(?:&&|\|\|) )(.+?) (contains) (.+?)(?= (?:&&|\|\|)|$)

https://regex101.com/r/YDFpN9/2

If you want 3 capture groups, you could match what you don't want first, and then capture in groups what you want to keep making use of a tempered greedy token approach to not cross matching && or || or the word contains.

\|{2,}|&{2,}|((?:(?!&&|\|\||\bcontains\b).)*) (contains) ((?:(?!&&|\|\||\bcontains\b).)*)

The pattern matches:

  • \|{2,}|&{2,} Match either 2 or more pipe chars or ampersands (what you don't want to keep)
  • | Or
  • ( Capture group 1
    • (?:(?!&&|\|\||\bcontains\b).)* Match any char except a newline if what is directly to the right is not && || or contains
  • ) Close group 1
  • (contains) Match the word contains in group 2 between spaces
  • ( Capture group 3
    • (?:(?!&&|\|\||\bcontains\b).)* Same approach as above
  • ) Close group 3

Regex demo

Related