skip to Main Content

Following the pattern from this article, I’m trying to create a regular expression that would capture some groups in arbitrary order.

/(?=.*(?<one>foo))(?=.*(?<two>bar))(?=.*(?<three>baz))/

However, the additional requirement is that the groups must be optional, i.e. it must match all the strings below:

foo bar baz
foo baz bar
baz bar foo
foo bar
foo baz
bar baz
foo
bar
baz

I tried applying a quantifier ? to the capturing group but for some reason it stops capturing that group completely. I’m wondering if that’s possible at all?

/(?=.*(?<one>foo)?)(?=.*(?<two>bar)?)(?=.*(?<three>baz)?)/

Here’s the demo at Regex101. Would appreciate any advice.

3

Answers


  1. Why not just use a global flag?

    const arr = `foo bar baz
    foo baz bar
    baz bar foo
    foo bar
    foo baz
    bar baz
    foo
    bar
    baz`.split('n');
    
    for(const str of arr){
      const result = [...str.matchAll(/(?<one>foo)|(?<two>baz)|(?<three>bar)/g)]
        .reduce((r, m) => (Object.entries(m.groups).forEach(([name, val]) => val && (r[name]=val)), r), {});
      console.log(result);
    }
    Login or Signup to reply.
  2. You can use non-greedy quantifiers for the wildcards:

    ^(?=(?:.*?(?<one>foo))?)(?=(?:.*?(?<two>bar))?)(?=(?:.*?(?<three>baz))?)
    

    Demo: https://regex101.com/r/Tiw8wu/1

    Login or Signup to reply.
  3. You can try this regex

    foo(?:sbar)?(?:sbaz)?|bar(?:sbaz)?|baz
    

    working demo with explaination

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search