0

I'm trying to match different urls to MVC actions of my controller.

Here is the current expression i'm testing:

#^/products((/([0-9]+)-([0-9a-z\_]+))*(/(index\.(html|pdf|xml|json))?)?)?$#i

When i try to match this to:

/products/22-test/25-test2

I was expecting to get (via preg_match_all) the following results:

array(5) {
  [0]=>
  string(26) "/products/22-test/25-test2"
  [1]=>
  string(17) "/22-test"
  [2]=>
  string(2) "22"
  [3]=>
  string(5) "test"
  [4]=>
  string(17) "/25-test"
  [5]=>
  string(2) "25"
  [6]=>
  string(5) "test2"
}

But instead i get

array(5) {
  [0]=>
  string(26) "/products/22-test/25-test2"
  [1]=>
  string(17) "/22-test/25-test2"
  [2]=>
  string(9) "/25-test2"
  [3]=>
  string(2) "25"
  [4]=>
  string(5) "test2"
}

UPDATE

The problem is that i'm not getting the category list translated into individual elements just so that i make my problem as clear as possible...

I'm using (/([0-9]+)-([0-9a-z\_]+))* in an attempt to transform as many category identifiers into a parsed item. Thats why i used (...)*, it should allow any number of categories to be matches and should match each of them no?

UPDATE 2

It seems that if i update the regexp to support many times the same category identifier, it gets parsed, i was hoping that (...)* would parse it many times instead of giving me one big list of category identifiers.

For example, this works fine:

#^/products((/([0-9]+)-([0-9a-z\_]+))?(/([0-9]+)-([0-9a-z\_]+))?(/([0-9]+)-([0-9a-z\_]+))?(/([0-9]+)-([0-9a-z\_]+))?(/([0-9]+)-([0-9a-z\_]+))?(/(index\.(html|pdf|xml|json))?)?)?$#i

But forces me to repeat the category selector MANY times. So if i have a client that decides to put more than X categories in his catalog, i'm blocked and the urls won't resolve correctly...

Is there any way to support that?

7
  • #^/products((/([0-9]+)-([0-9a-z\_\-]+))*(/(index\.(html|pdf|xml|json))?)?)?$#i Try That Commented Feb 2, 2012 at 19:16
  • Nope, i tried it anyway although i was sure the \- wouldnt change it. The problem is that i'm not getting the category list translated into individual elements Commented Feb 2, 2012 at 19:18
  • Darn i think i found it... i have to repeat the category selector many times. So i have to hope that my clients will never use more than X categories deep or it will stop working... Is there any other way? Commented Feb 2, 2012 at 19:22
  • 2
    You're using repetition on a subpattern, so the subpattern match will only be populated with the last match, as it is overwritten in each successive repetition. Commented Feb 2, 2012 at 19:23
  • Does it have to be done in a single regex operation? If not, you could match the entire part between "products" and the page name, then split that string on slashes. Commented Feb 2, 2012 at 19:28

2 Answers 2

2

The result is a positional result. I.e. Position 1 captures the first (), position 2 captures the second set of ().

A * makes the capture group larger, but doesn't multiply the positions.

You might want to just split the first group using a "findall" with (/([0-9]+)-([0-9a-z\_]+)) in a second step.

Sign up to request clarification or add additional context in comments.

3 Comments

Apart from repeating the selector, is there any other way to achieve what i want?
Yes. findAll on the first group with the regular expression of the first group only.
ok.... shucks... changes my route object substantially i think, i'll have to review that. I'll wait to see if there are other solutions that might popup but that seems the only one so far...
0

Consider this code to get individual categories id and name:

$str = '/products/22-test/25-test2';
if (stripos($str, "/products/") !== false &&
    preg_match_all('#(/(\d+)-([a-z\d_-]+))#i', $str, $m))
   print_r($m);

OUTPUT:

Array
(
    [0] => Array
        (
            [0] => /22-test
            [1] => /25-test2
        )

    [1] => Array
        (
            [0] => 22
            [1] => 25
        )

    [2] => Array
        (
            [0] => test
            [1] => test2
        )

)

2 Comments

It would work with your solution but won't in my case cause i use a match to detect which action i need to execute and detect the sub information at the same time.
You could do something like if (stripos($str, "/products/") !== false && preg_match_all('#(/(\d+)-([a-z\d_-]+))#i', $str, $m)) as in my updated answer as well.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.