views:

227

answers:

2

Regular expressions is just not my thing. :(

I have a string that may contain multiple sub strings such as:

[var1="111" var2="222" var3="222" var4="444"]

I basically need to replace each occurrence with the the results of a function that gets each variable.

$string = '[var1="111" var2="222" var3="333" var4="444"]';    
$regex = 'var1="(.*)" var2="(.*)" var3="(.*)" var4="(.*)"';

function doit($matches){
    return "<strong>".implode(", ", $matches) ."</strong>";
}

echo preg_replace_callback($regex,'doit',$string);

I’m expecting 111, 222, 333, 444.

But I’m not feeling the love. Any help would be appreciated!

Edit: some clarification..

I was simplifying for the sake of the question.

  1. the "vars" will not really be called "var1", "var2" more like [recID="22" template="theName" option="some value", type="list"]

  2. the call back would be more complicated then my simple implode... I would use "id" and connect to a database, get the records and insert them into the template... Hence the need for the call back...

  3. matched values could be almost anything, not just numbers.

A: 

The other answer may be a better solution, but here is how you could do it with preg_replace_callback:

$string = '[var1="111" var2="222" var3="333" var4="444"]';

// Note: regular expressions need to start and end with /
$regex = '/var1="(.*)" var2="(.*)" var3="(.*)" var4="(.*)"/';

function doit($matches){
    // The first element of matches is the complete
    // match, shift is here just to get rid of it
    // (probably a better way to do this)
    array_shift($matches);
    return "<strong>".implode(", ", $matches) ."</strong>";
}
echo preg_replace_callback($regex,'doit',$string);
Eric
In order to account for the brackets, the $regex should actually be:$regex = "/\[var1=\"(.*)\" var2=\"(.*)\" var3=\"(.*)\" var4=\"(.*)\"\]/";
Eric
Perfect! Thanks.. any issues I might run into using (.*)?? Any characters I should be careful about? - Obviously a " in there would be an issue! :-)
Alex
A: 

I would do it in two step:

  1. Get the tags
  2. Get the attributes for each tag

Here’s an example:

function doit($match) {
    $parts = preg_split('/(\w+="[^"]*")/', $match[1], -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
    foreach ($parts as $part) {
        if (trim($part) !== "") {
            if (!preg_match('/^(\w+)="([^"]*)"$/', $part, $match)) {
                // syntax error
            } else {
                var_dump($match);
            }
        }
    }
}

$str = '[var1="111" var2="222" var3="333" var4="444"]';
$re = '/\[((?:[^"[\]]+|"[^"]*")*)]/';
preg_replace_callback($re, 'doit', $str);

With this you can even detect syntax errors.

It’s not a perfect solution as it would be more efficient to read the input character by character and determine the tokens depending on the contexts they are found in.

Gumbo
Gumbo, great approach! This works perfect for me, as it can be used in multiple cases with different tags. also the order is not critical. Nice. Would love to chat with you more about your "more perfect" solution. If you have some time I can be reached at alex [at] incontrolsolutions.com
Alex
This has been working "almost" perfect for me.. Thanks. Using like $content2 = preg_replace_callback('/\[((?:[^"[\]]+|"[^"]*")*)]/', 'WCMS_InsertCustomTemplate', $content2);But It is there a way to get it to ignore anything inside <script> tags??
Alex
@Alex: If you’re dealing with HTML, you should use a HTML parser to only get the contents of specific elements.
Gumbo
@Gumbo, my $content2 sting is coming from a database.. In some (rare) casses there may be a <script> tag within that code... the "[var1="111" var2="222" var3="333" var4="444"]" part I am tring to isolate is not wrapped in any particular HTML tag. If your around can you skype me? skype=alexduffield woudlbe happy to pay for your time/help!
Alex
@Alex: But you can use an HTML parser and get the contents except those that are in a `script` element.
Gumbo