Регулярное выражение для получения повторяющихся совпадений внутри совпадения

У меня есть эта примерная строка в источнике: @include_plugin:PluginName param1=value1 param2=value2@

Я хочу найти все вхождения @include_plugin:*@ из источника с результатом PluginName и каждого paramN=valueN.

В данный момент я возился с чем-то вроде этого (и пробовал много вариантов): /@include_plugin:(.*\b){1}(.*\=.*){0,}@/ (используя этот ресурс). К сожалению, я не могу определить шаблон, который дает мне желаемый результат. Какие-либо предложения?

Обновление с примером: Допустим, у меня есть эта строка в .tpl-файле. @include_plugin:BestSellers limit=5 fromCategory=123@

Я хочу, чтобы он возвращал массив с:

0 => BestSellers, 
1 => limit=5 fromCategory=123 

Или еще лучше (если возможно):

0 => BestSellers, 
1 => limit=5, 
2 => fromCategory=123

person Ben Fransen    schedule 10.08.2012    source источник
comment
Какой узор вы хотите получить? а что ты получишь обратно в preg_match?   -  person gmaliar    schedule 10.08.2012
comment
Извини, братан, но то, что ты описываешь в «Или даже лучше», невозможно. У вас не может быть переменного количества совпадающих групп в регулярном выражении. см. объяснение на stackoverflow.com/a/5019658/227887.   -  person Geoffrey Bachelet    schedule 10.08.2012
comment
@GeoffreyBachelet: это возможно, если известно максимальное количество параметров. (В общем случае невозможно).   -  person nhahtdh    schedule 10.08.2012
comment
Ну да, я предположил (возможно, ошибочно), что количество параметров в примере OP было произвольным   -  person Geoffrey Bachelet    schedule 11.08.2012


Ответы (5)


Вы можете сделать это в 2 шага. Сначала захватите строку с помощью регулярного выражения, а затем взорвите параметры в массив:

$subject = '@include_plugin:PluginName param1=value1 param2=value2@';
$pattern = '/@include_plugin:([a-z]+)( .*)?@/i';
preg_match($pattern, $subject, $matches);

$pluginName = $matches[1];
$pluginParams = isset($matches[2])?explode(' ', trim($matches[2])):array();
person Tchoupi    schedule 10.08.2012
comment
Это приятно! Он делает то, что я хочу, но еще один вопрос. Возможно ли также, чтобы раздел param был необязательным? Не каждый плагин имеет определенные параметры. Или я должен затем запустить 2 регулярных выражения и проверить, есть ли у него параметры? - person Ben Fransen; 10.08.2012
comment
По сути, он также должен быть в состоянии найти @include_plugin:SomePlugin@ - person Ben Fransen; 10.08.2012
comment
Спасибо за помощь! Я использовал preg_match_all, чтобы получить то, что я хочу, потому что может быть несколько плагинов. +1 и принято. - person Ben Fransen; 10.08.2012
comment
@BenFransen Нет проблем. Конечно, preg_match_all и цикл подойдут. - person Tchoupi; 10.08.2012

Вы можете использовать это регулярное выражение:

/@include_plugin:([a-zA-Z0-9]+)(.*?)@/

PluginName находится в первой группе захвата, а параметры — во второй группе захвата. Обратите внимание, что параметры, если они есть, имеют начальные пробелы.

Невозможно написать регулярное выражение для извлечения в вашем еще лучшем случае, если только не известно максимальное количество параметров.

Вы можете выполнить дополнительную обработку, сначала обрезав начальные и конечные пробелы, а затем разделив их по /\s+/.

person nhahtdh    schedule 10.08.2012
comment
Спасибо за ваш ответ, но он возвращает все после : и до второго @. Что, к сожалению, не то, что мне нужно. - person Ben Fransen; 10.08.2012
comment
@BenFransen: вы можете выполнить дополнительную обработку позже. Я даже не знаю о разрешенных символах в PluginName, поэтому самое большее, что я могу сделать, это изменить регулярное выражение, чтобы захватить все после include_plugin. - person nhahtdh; 10.08.2012
comment
Я знаю, но мне было интересно, можно ли это сделать в регулярном выражении (см. Пример обновленного вопроса). В противном случае я всегда могу обработать строку, взорвав ее. Допустимые символы для PluginName: [a-zA-Z0-9] - person Ben Fransen; 10.08.2012
comment
@BenFransen: отредактировал мой ответ. - person nhahtdh; 10.08.2012

Я не уверен в вашем наборе символов, который может содержать ваш PluginName, или в параметрах/значениях, но в случае, если они ограничены, вы можете использовать следующее регулярное выражение:

/@include_plugin:((?:\w+)(?:\s+[a-zA-Z0-9]+=[a-zA-Z0-9]+)*)@/

Это зафиксирует имя плагина, за которым следует любой список буквенно-цифровых параметров с их значениями. Вывод можно увидеть с помощью:

<?
$str = '@include_plugin:PluginName param1=value1 param2=value2@
@include_plugin:BestSellers limit=5 fromCategory=123@';

$regex = '/@include_plugin:((?:\w+)(?:\s+[a-zA-Z0-9]+=[a-zA-Z0-9]+)*)@/';

$matches = array();
preg_match_all($regex, $str, $matches);

print_r($matches);
?>

Это выведет:

Array
(
    [0] => Array
        (
            [0] => @include_plugin:PluginName param1=value1 param2=value2@
            [1] => @include_plugin:BestSellers limit=5 fromCategory=123@
        )

    [1] => Array
        (
            [0] => PluginName param1=value1 param2=value2
            [1] => BestSellers limit=5 fromCategory=123
        )

)

Чтобы получить массив в нужном вам формате, вы можете перебрать результаты с помощью:

$plugins = array();
foreach ($matches[1] as $match) {
    $plugins[] = explode(' ', $match);
}

И теперь у вас будет следующее в $plugins:

Array
(
    [0] => Array
        (
            [0] => PluginName
            [1] => param1=value1
            [2] => param2=value2
        )

    [1] => Array
        (
            [0] => BestSellers
            [1] => limit=5
            [2] => fromCategory=123
        )

)
person newfurniturey    schedule 10.08.2012
comment
Спасибо за ваш вклад. Очень ясно! Спасибо + 1, Accept переходит к Матье. - person Ben Fransen; 10.08.2012

$string = "@include_plugin:PluginName1 param1=value1 param2=value2@ @include_plugin:PluginName2@";

preg_match_all('/@include_plugin:([a-zA-Z0-9]+)\s?([^@]+)?/', $string, $matches);
var_dump($matches);

Это то, что вы ищите?

array(3) {
  [0]=>
  array(2) {
    [0]=>
    string(55) "@include_plugin:PluginName1 param1=value1 param2=value2"
    [1]=>
    string(27) "@include_plugin:PluginName2"
  }
  [1]=>
  array(2) {
    [0]=>
    string(11) "PluginName1"
    [1]=>
    string(11) "PluginName2"
  }
  [2]=>
  array(2) {
    [0]=>
    string(27) "param1=value1 param2=value2"
    [1]=>
    string(0) ""
  }
}
person Leon Kramer    schedule 10.08.2012
comment
Нет, но спасибо за ваши усилия. См. ответ Мэтью, который делает то, что я ищу, с 1 дополнительным (неупомянутым требованием): находит совпадения без определенных параметров. - person Ben Fransen; 10.08.2012
comment
Спасибо за помощь, +1 - person Ben Fransen; 10.08.2012

Это регулярное выражение даст вам несколько групп, по одной для каждого плагина.

((?<=@include_plugin:)(.+))
person Mike Perrenoud    schedule 10.08.2012