Search code examples
phpregexpcrerestful-urlsymfony-routing

How can I write a regexp that recursively matches RESTful path?


Regexp being not my strength, I would like some help on this one, if it is even possible:

I need to create a regexp that recursively matches a RESTful path. The purpose is to create a Symfony route matching this regexp. Here is some examples of what I mean by RESTful path:

/resources
/resources/123
/resources/123/children-resources
/resources/123/children-resources/123
/resources/123/children-resources/123/grandchildren-resources

And so on...

Basically, I would like this pattern to repeat itself indefinitly one or more time:

^\/[a-z]+(\-[a-z]+)*(\/[0-9]+)?$

Note that to access to a child resource, the identifier of the parent resource must be present.

I made a short list of unit tests (for two-level paths only to start) here: https://regex101.com/r/Hxg0m4/2/tests

I searched questions on the same subject, but none were really relevant to my question. I also tried some modifications on the regexp above - like using the + sign at the end of the regexp, or use (?R)... It never passed my unit tests.

Any help will be gladly appreciated.

P.S: This is my first question on stackoverflow, please don't hesitate to tell me how to better formulate my question.


Solution

  • This recursive pattern should work:

    ^(\/[a-z]+(?:-[a-z]+)*(?:$|\/\d+(?:$|(?1))))
    

    Explanation:

    ^                       // assert start of string
    (
        \/                  // start with a slash
        [a-z]+(?:-[a-z]+)*  // followed by a word
        (?:                 // then, either:
            $               // end of string
        |                   // or:
            \/              // a slash
            \d+             // followed by digits
            (?:             // then, either:
                $           // end of string
            |               // or:
                (?1)        // recurse the entire pattern (except the start of string anchor)
            )
        )
    )