Mathieu Dumoulin
Mathieu Dumoulin

Reputation: 12244

Regular expression not matching url as expected

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?

Upvotes: 0

Views: 110

Answers (2)

anubhava
anubhava

Reputation: 786349

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
        )

)

Upvotes: 0

Has QUIT--Anony-Mousse
Has QUIT--Anony-Mousse

Reputation: 77505

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.

Upvotes: 2

Related Questions