Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Regex: Ignore order of capture groups and capture only last occurrence

Tags:

regex

Let's say we have the following string:

1|order=asc|type=1

We need to create regex that will parse it to parameters assuming that string always should start with number and will (optionally) have parameters (order, asc) in any order. Also it may have 3 and more parameters but let's keep 2 here for simplicity. For instance these are the string that regex will understand:

1
1|order=asc|type=1
1|type=1|order=asc

I have the following expression that does this job:

(?<id>^\w+)((?:\|type=(?<type>\w+))|(?:\|order=(?<order>\w+))){0,2}

This is demo link to my regex

But the issue is that it allows duplicates.

If we have the following string it will not match order parameter at all:

1|type=1|type=2|order=asc

Ideally we should have the following groups from regex above:

  • id:1
  • type:2 (as it should capture last occurrence)
  • order:asc
like image 610
valchetski Avatar asked Sep 07 '25 05:09

valchetski


1 Answers

You can use

^(?<id>\w+)(?:\|(?:type=(?<type>\w+)|order=(?<order>\w+)))*$

See the regex demo.

Details:

  • ^ - string start
  • (?<id>\w+) - Group "id": one or more word chars
  • (?:\|(?:type=(?<type>\w+)|order=(?<order>\w+)))* - zero or more repetitions of
    • \| - a | char
    • (?:type=(?<type>\w+)|order=(?<order>\w+)) - either of
      • type=(?<type>\w+)| - type= text, then Group "type" capturing one or more word chars, and then an OR operator
      • order= - text order= and then
      • (?<order>\w+) - Group "order": one or more word chars
  • $ - string end.

The capturing groups inside the (?:...)* repeated group will keep re-writing the group values each time they capture a string and thus the last occurrences will be kept.

You can enhance this regex by adding more groups inside the second non-capturing group. For example, adding num and status is as easy as

^(?<id>\w+)(?:\|(?:type=(?<type>\w+)|order=(?<order>\w+)|num=(?<num>\d+)|status=(?<status>\w+)))*$

See this regex demo.

like image 125
Wiktor Stribiżew Avatar answered Sep 10 '25 11:09

Wiktor Stribiżew