Get repeated matches with preg_match_all()

2019-01-15 18:55发布

问题:

I'm trying to get all substrings matched with a multiplier:

$list = '1,2,3,4';
preg_match_all('|\d+(,\d+)*|', $list, $matches);
print_r($matches);

This example returns, as expected, the last match in [1]:

Array
(
    [0] => Array
        (
            [0] => 1,2,3,4
        )

    [1] => Array
        (
            [0] => ,4
        )

)

However, I would like to get all strings matched by (,\d+), to get something like:

Array
(
    [0] => ,2
    [1] => ,3
    [2] => ,4
)

Is there a way to do this with a single function such as preg_match_all()?

回答1:

According to Kobi (see comments above):

PHP has no support for captures of the same group

Therefore this question has no solution.



回答2:

Using lookbehind is a way to do the job:

$list = '1,2,3,4';
preg_match_all('|(?<=\d),\d+|', $list, $matches);
print_r($matches);

All the ,\d+ are in group 0.

output:

Array
(
    [0] => Array
        (
            [0] => ,2
            [1] => ,3
            [2] => ,4
        )
)


回答3:

You can't, use a split on , (as Kobi said).



回答4:

Why not just:

$ar = explode(',', $list);
print_r($ar);


回答5:

Splitting is only an option when the character to split isn't used in the patterns to match itself. I had a situation where a badly formatted comma separated line has to be parsed into any of a number of known options.

i.e. options '1,2', '2', '2,3' subject '1,2,3'.

Splitting on ',' will result in '1', '2', and '3'; only one ('2') of which is a valid match, this happens because the separator is also part of the options.

The naïve regex would be something like '~^(1,2|2|2,3)(?:,(1,2|2|2,3))*$~i', but this runs into the problem of same-group captures.

My "solution" was to just expand the regex to match the maximum number of matches possible: '~^(1,2|2|2,3)(?:,(1,2|2|2,3))?(?:,(1,2|2|2,3))?$~i' (if more options were available, just repeat the '(?:,(1,2|2|2,3))?' bit. This does result in empty string results for "unused" matches.

It's not the cleanest solution, but works when you have to deal with badly formatted input data.



回答6:

From http://www.php.net/manual/en/regexp.reference.repetition.php :

When a capturing subpattern is repeated, the value captured is the substring that matched the final iteration.

Also similar thread:

How to get all captures of subgroup matches with preg_match_all()?