1

I am trying to create a regular expression that only matches when a string consists of instances of some pattern. Let's say that I only need a string to consist of "foo" or "bar" substrings separated by a space.

So, valid instances are: "foo", "bar", "foo foo", "foo bar", "foo foo bar", "foo bar foo bar"... Invalid instances: "foofoo bar", "baz foo bar", "foo bar baz"

Thus, each instance of foo or bar (i.e. my base pattern or capture group), should be preceded by either a space or be at the start of string, and it should be ended either with a space, or be located at the end of the string.

It seemed like a simple task, but I can't figure it out.

This is what I got so far:

(?:^|bar\s|foo\s)(foo|bar)(?=$|\sbar|\sfoo)

It doesn't work on "foofoo bar" (somehow it's valid).

I'm testing it in Python. But it would be good if it worked in JS too.

Ray P.
  • 875
  • 1
  • 9
  • 24

1 Answers1

1

You may use a pattern like

^(?:foo|bar)(?: (?:foo|bar))*$

See regex demo #1

If your regex engine supports recursive patterns you may use

^(?<id>foo|bar)(?: (?&id))*$

See regex demo #2

NOTE:

  • If you have a problem with a trailing newline matched, you need to adjust the end of string anchor (see this answer of mine)
  • If you need to allow any 1+ whitespace chars between the entries, use \s+. If the whitespace should not match line breaks use \h+ or [\p{Zs}\t]+. If there can only be 1 whitespace between the entries remove the +.
  • To allow leading/trailing whitespace, add the \s* / \h* / [\p{Zs}\t]* after ^ and before $.
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
  • Thank you. Could that recursive pattern functionality be reproduced with ECMA Script flavour? I'm trying to adapt your example, but it doesn't work. – Ray P. Dec 06 '19 at 10:07
  • 1
    @RayP. ECMAScript does not support recursion. If you work in JS, just [build the pattern dynamically](https://stackoverflow.com/a/50553431/3832970). – Wiktor Stribiżew Dec 06 '19 at 10:11
  • unfortunatelly, I have to use this pattern in a JSON schema, so I would not be able to build it dynamically. Nonetheless, thanks for the explanation. – Ray P. Dec 06 '19 at 10:18