Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

308
Views
python regex where a set of options can occur at most once in a list, in any order

I'm wondering if there's any way in python or perl to build a regex where you can define a set of options can appear at most once in any order. So for example I would like a derivative of foo(?: [abc])*, where a, b, c could only appear once. So:

foo a b c
foo b c a
foo a b
foo b

would all be valid, but

foo b b

would not be

over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

You may use this regex with a capture group and a negative lookahead:

For Perl, you can use this variant with forward referencing:

^foo((?!.*\1) [abc])+$

RegEx Demo

RegEx Details:

  • ^: Start
  • foo: Match foo
  • (: Start a capture group #1
    • (?!.*\1): Negative lookahead to assert that we don't match what we have in capture group #1 anywhere in input
    • [abc]: Match a space followed by a or b or c
  • )+: End capture group #1. Repeat this group 1+ times
  • $: End

As mentioned earlier, this regex is using a feature called Forward Referencing which is a back-reference to a group that appears later in the regex pattern. JGsoft, .NET, Java, Perl, PCRE, PHP, Delphi, and Ruby allow forward references but Python doesn't.


Here is a work-around of same regex for Python that doesn't use forward referencing:

^foo(?!.* ([abc]).*\1)(?: [abc])+$

Here we use a negative lookahead before repeated group to check and fail the match if there is any repeat of allowed substrings i.e. [abc].

RegEx Demo 2

over 4 years ago · Santiago Trujillo Report

0

You can assert that there is no match for a second match for a space and a letter at the right:

foo(?!(?: [abc])*( [abc])(?: [abc])*\1)(?: [abc])*
  • foo Match literally
  • (?! Negative lookahead
    • (?: [abc])* Match optional repetitions of a space and a b or c
    • ( [abc]) Capture group, use to compare with a backreference for the same
    • (?: [abc])* Match again a space and either a b or c
    • \1 Backreference to group 1
  • ) Close lookahead
  • (?: [abc])* Match optional repetitions or a space and either a b or c

Regex demo

If you don't want to match only foo, you can change the quantifier to 1 or more (?: [abc])+


A variant in perl reusing the first subpattern using (?1) which refers to the capture group ([abc])

^foo ([abc])(?: (?!\1)((?1))(?: (?!\1|\2)(?1))?)?$

Regex demo

over 4 years ago · Santiago Trujillo Report

0

If it doesn't have to be a regex:

import collections

# python >=3.10
def is_a_match(sentence):
    words = sentence.split()
    return (
      (len(words) > 0)
      and (words[0] == 'foo')
      and (collections.Counter(words) <= collections.Counter(['foo', 'a', 'b', 'c']))
    )

# python <3.10
def is_a_match(sentence):
    words = sentence.split()
    return (
      (len(words) > 0)
      and (words[0] == 'foo')
      and not (collections.Counter(words) - collections.Counter(['foo', 'a', 'b', 'c']))
    )

# TESTING
#foo a b c True
#foo b c a True
#foo a b True
#foo b True
#foo b b False

Or with a set and the walrus operator:

def is_a_match(sentence):
    words = sentence.split()
    return (
      (len(words) > 0)
      and (words[0] == 'foo')
      and (
        (s := set(words[1:])) <= set(['a', 'b', 'c'])
        and len(s) == len(words) - 1
      )
    )
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!