Получить повторные матчи с preg match all()


Я пытаюсь получить все подстроки, соответствующие множителю:

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

Этот пример возвращает, как и ожидалось, последнее совпадение в [1]:

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

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

)

Однако, я хотел бы получить все строки, соответствующие (,d+), чтобы получить что-то вроде:

Array
(
    [0] => ,2
    [1] => ,3
    [2] => ,4
)
Есть ли способ сделать это с помощью одной функции, такой как preg_match_all()?
6 9

6 ответов:

Согласно Коби (см. комментарии выше):

PHP не поддерживает захваты одной и той же группы

Поэтому этот вопрос не имеет решения.

Использование lookbehind - это способ выполнить работу:

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

Все ,\d+ находятся в группе 0.

Вывод:

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

Вы не можете, используйте разделение на , (как сказал Коби).

Почему бы не просто:

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

Разбиение-это только вариант, когда символ для разбиения не используется в шаблонах, чтобы соответствовать самому себе. У меня была ситуация, когда плохо отформатированная строка, разделенная запятыми, должна быть разбита на любой из известных вариантов.

То есть варианты '1,2', '2', '2,3' тема '1,2,3'.

Разбиение на ', ' приведет к '1', '2' и '3'; только один ('2') из которых является допустимым соответствием, это происходит потому, что разделитель также является частью опций.

Наивное регулярное выражение было бы чем-то как будто '~^(1,2|2|2,3)(?:,(1,2|2|2,3))*$~i', но это упирается в проблему одногруппных захватов.

Мое "решение" состояло в том, чтобы просто расширить регулярное выражение, чтобы соответствовать максимальному количеству возможных совпадений: '~^(1,2|2|2,3)(?:,(1,2|2|2,3))?(?:,(1,2|2|2,3))?$~i' (если были доступны другие варианты, просто повторите' (?:,(1,2|2|2,3))?' немного. Это приводит к пустой строке результатов для "неиспользуемых" матчей.

Это не самое чистое решение, но работает, когда вам приходится иметь дело с плохо отформатированным входом данные.

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

Когда подшаблон захвата повторяется, захваченное значение является подстрокой, которая соответствовала последней итерации.

Также аналогичная нить:

Как получить все записи матчей подгрупп с помощью preg_match_all()?