Reputation: 1217
Here is my problem: I have a php file which contain this "html" code:
<div>
{{ '{# Hi :D #}' }} {# Hello #}
{{ $model }}
</div>
In my code I want to get the {# #} and the {{ }} to do different regex replacement but not the one that are in {{ }}.
The problem here is that if I do in the same (in PHP) preg_replace for the two possible match, this doesn't take the {{ }} found (That's what I want) but the replacement will be the same for the two:
/{{(.*?)}}|{#(.*?)#}/
This is logic but I want to do different replacements for each $1 and $2 match.
I thought to those possibilities :
After 2 days trying to create this magic regex I finally ask a question in stackoverflow, hope someone will found the answer to this regex
Thanks,
Upvotes: 1
Views: 71
Reputation: 1447
EDITED
Here's an approach using preg_split()
with PREG_SPLIT_DELIM_CAPTURE
flag in order to tokenize the string and account for nested tags.
$tokens = [
// token definition as [open_tag, close_tag, replacement]
['{{', '}}', '<?php echo \1; ?>'],
['{#', '#}', '<?php //\1 ?>']
];
$open_tags = array_column($tokens, 0);
$close_tags = array_column($tokens, 1, 0); // mapped by open tag
$replacements = array_column($tokens, 2, 0); // mapped by open tag
$token_regex = '/(' . implode('|', array_map('preg_quote', $open_tags + $close_tags)) . ')/';
$parts = preg_split($token_regex, $input, -1, PREG_SPLIT_DELIM_CAPTURE);
$output = '';
while (null !== ($part = array_shift($parts))) {
// open tag found...
if (in_array($part, $open_tags)) {
// ...start building string of full tag
$tag_body = $part;
// ...watch for corresponding close tag
$close_at = [ $close_tags[$part] ];
while (0 < count($close_at)) {
$inner_part = array_shift($parts);
if (in_array($inner_part, $open_tags)) {
// nested tag found, add its closing to watchlist
array_unshift($close_at, $close_tags[$inner_part]);
} else {
// close tag found, remove from watchlist
if (reset($close_at) === $inner_part) {
array_shift($close_at);
}
}
$tag_body .= $inner_part;
}
// substitute full tag with replacement
$tag_regex = '/^' . preg_quote($part) . '\s*(.*?)\s*' . preg_quote($close_tags[$part]) . '$/';
$part = preg_replace($tag_regex, $replacements[$part], $tag_body);
}
$output .= $part;
}
echo $output;
You can try it out here.
Upvotes: 2