2

I have this sample string in a source: @include_plugin:PluginName param1=value1 param2=value2@

What I want is to find all occurances of @include_plugin:*@ from a source with a result of the PluginName and each paramN=valueN.

At this moment I'm fiddling with something like this (and have tried many variants): /@include_plugin:(.*\b){1}(.*\=.*){0,}@/ (using this resource). Unfortunately I can't seem to define a pattern which is giving me the result I want. Any suggestions?

Update with example: Say I have this string in a .tpl-file. @include_plugin:BestSellers limit=5 fromCategory=123@

I want it to return an array with:

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

Or even better (if possible):

0 => BestSellers, 
1 => limit=5, 
2 => fromCategory=123
Ben Fransen
  • 10,884
  • 18
  • 76
  • 129
  • What pattern do you want to get? and what do you get back in the preg_match? – gmaliar Aug 10 '12 at 13:02
  • Sorry bro but what you describe in "Or even better" is not possible. You can't have a variable number of matching groups in a regexp. see http://stackoverflow.com/a/5019658/227887 for an explanation. – Geoffrey Bachelet Aug 10 '12 at 13:21
  • 1
    @GeoffreyBachelet: It is possible if the maximum number of parameters is known. (Not possible in general case). – nhahtdh Aug 10 '12 at 14:39
  • Well yes, I assumed (maybe wrongly) that the number of parameters in OP's example was arbitrary – Geoffrey Bachelet Aug 10 '12 at 23:04

5 Answers5

3

You can do it in 2 steps. First capture the line with a regex, then explode the parameters into an array:

$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();
Tchoupi
  • 14,560
  • 5
  • 37
  • 71
  • This is nice! It does what I want, but one more question. Is it also possible to have the param-section optional? Not every plugin has params defined. Or should I then fire 2 regex-calls and check wether or not it has params? – Ben Fransen Aug 10 '12 at 13:13
  • Basically it should also be able to find `@include_plugin:SomePlugin@` – Ben Fransen Aug 10 '12 at 13:13
  • Thanks for you help! I've used a preg_match_all to get what I want, because there can be multiple plugin includes. +1 and accepted. – Ben Fransen Aug 10 '12 at 13:23
  • @BenFransen No problem. Of course a `preg_match_all` and a loop will do. – Tchoupi Aug 10 '12 at 13:24
1

You can use this regex:

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

The PluginName is in the first capturing group, and the parameters are in the second capturing group. Note that the parameters, if any, has a leading spaces.

It is not possible to write a regex to extract to your even better case, unless the maximum number of parameters in known.

You can do extra processing by first trimming leading and trailing spaces, then split along /\s+/.

nhahtdh
  • 55,989
  • 15
  • 126
  • 162
  • Thanks for your answer, but it's returning everything after : and before the second @. Which, unfortunately, is not what I'm after. – Ben Fransen Aug 10 '12 at 13:03
  • @BenFransen: You can do extra processing later. I don't even know about the allowed characters in PluginName, so the most I can do is modify the regex to capture everything after `include_plugin`. – nhahtdh Aug 10 '12 at 13:06
  • I know, but I was wondering if this can be done within the regex (see updated question for an example). Otherwise I can always process the string by exploding it. Allowed chars for PluginName are `[a-zA-Z0-9]` – Ben Fransen Aug 10 '12 at 13:08
1
$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);

is this what you are looking for?

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) ""
  }
}
Leon Kramer
  • 486
  • 3
  • 13
  • No, but thanks for the effort you're taking. See Mathieuw's answer, that one does what I'm looking for with 1 extra (non-mentioned requirement): find matches without params defined. – Ben Fransen Aug 10 '12 at 13:15
1

I'm not sure of your character-set that your PluginName can contain, or the parameters/values, but in case they are limited you can use the following regex:

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

This will capture the plugin name followed by any list of alpha-numeric parameters with their values. The output can be seen with:

<?
$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);
?>

This will output:

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
        )

)

To get the array in the format you need, you can iterate through the results with:

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

And now you'll have the following in $plugins:

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

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

)
newfurniturey
  • 37,556
  • 9
  • 94
  • 102
0

This Regex will give you multiple groups, one for each plugin.

((?<=@include_plugin:)(.+))
Mike Perrenoud
  • 66,820
  • 29
  • 157
  • 232