Reputation: 4705
i use this pattern '/(\{(\w+)\}(.*))?\{%(\w+)%\}((.*)\{\/(\w+)\})?/i'
to extract tags from a template using preg_match
function.
sample template:
<table id="middle" cellspacing="0px" cellpadding="0px">
{middle}
<tr>
{left}<td>{%left%}</td>{/left}
<td>{%middle%}{%content%}</td>
{right}<td>{%right%}</td>{/right}
</tr>
{/middle}
</table>
how to make sure that start
and end
of each tag truly match it's name
in this example middle
tag matches for both middle
and content
while it should just match middle
tag
Upvotes: 1
Views: 1030
Reputation: 24969
I think the best way to solve this problem would be do this in a few different steps.
First, you should use preg_replace_callback with /(?>{([^}]+)})(.*)?{\/\1}/sim
as your regular expression. This will find the top level {tag}{/tag}. The $matches[2] will contain the content (without the tags) while $matches1 will contain the tag itself.
You should create a function that's called recursively so that in the callback, it's called again on $matches[2] so find the children {tags} just in case there are more. This is how you'll go through the tree.
Finally, you should make a third function that handles the {%tag%}. I would use preg_replace_callback again and make use of the switch statement to handle the tag name.
This should point you in the right direction.
EDIT: Here is a fully functional demo of what I described above:\
<?php
$content = <<<END
{a}
{b}I like {%first%} {%last%} a {c}lot{/c}.{/b}
{/a}
END;
echo find_tags($content);
function find_tags($content)
{
return preg_replace_callback('/(?>{([^}]+)})(.*)?{\/\1}/sim', 'find_tags_callback', $content);
}
function find_tags_callback($matches)
{
// Find and process any children tag pairs.
$matches[2] = find_tags($matches[2]);
// Process the tags {%tag%}.
$matches[2] = preg_replace_callback('/{%([^%]+)%}/sim', 'process_tags', $matches[2]);
switch ( $matches[1] )
{
case 'a':
$tag = 'div';
break;
case 'b':
$tag = 'p';
break;
case 'c':
$tag = 'b';
break;
}
return '<'.$tag.'>'.$matches[2].'</'.$tag.'>';
}
function process_tags($matches)
{
switch ( $matches[1] )
{
case 'first':
return 'Francois';
break;
case 'last':
return 'Deschenes';
break;
}
}
//
The resulting string will be: <div><p>I like Francois Deschenes a <b>lot</b>.</p></div>
.
Upvotes: 1
Reputation: 87
1I'm confident, but not certain, that to make sure the enclosing tags({this}{/this}) match the data tags ({%this%}), you would need an accompanying if statement to test the returned strings.
I would use the preg_replace_callback function, like so:
<?php
$str = '<template contents>';
$newstr = preg_replace_callback(
'/(\{(\w+)\}(.*))?\{%(\w+)%\}((.*)\{\/(\w+)\})?/i',
'check', //<-- the function to send matches to
$str);
function check($matches){
if($matches[1] == $matches[2] && $matches[1] == $matches[3]){
/*Do Work*/
return ''; //new formatted string to send back to the $newstr var
}
}
?>
the preg_replace_callback function sends any matches found as an array to the specified function for processing, then you return the new formatted string from that function.
Upvotes: 0