PHP preg_match_all search and replace
This is a very good case for using preg_replace_callback()
but first let's polish your regex:
Get rid of the
e
modifier, it's deprecated and you don't need it since we're going to usepreg_replace_callback()
/\{\{\$(\w+)\}\}/
We don't need to escape
{{}}
in this case, PCRE is smart enough to tell that they are not meant as quantifiers/{{\$(\w+)}}/
Since you got dots in your input, we need to change
\w
otherwise it will never match.[^}]
is perfect since it means match anything except}
/{{\$([^}]+)}}/
I tend to use different delimiters, this is not required:
#{{\$([^}]+)}}#
Let's get to serious business, the use
identifier is going to be of great help here:
$replaces = array('testa.testb.testc' => '1', 'testc.testa' => '2', 'testf' => '3');
$text = '{{$testa.testb.testc}}<br>{{$testc.testa}}<br>{{$testf}}<br>{{$aaaaa}}<br>';
$output = preg_replace_callback('#{{\$([^}]+)}}#', function($m) use ($replaces){
if(isset($replaces[$m[1]])){ // If it exists in our array
return $replaces[$m[1]]; // Then replace it from our array
}else{
return $m[0]; // Otherwise return the whole match (basically we won't change it)
}
}, $text);
echo $output;
Online regex demo Online php demo
Well you are just using $matches
and not $matches[0]
, that's why the code you posted does not work.
And your regex doesn't count the .
with the \w
, so let'z try with [\w.]+
(I used $matches[1]
that contains directly the key we need, and then we don't need to use str_replace 2 times more)
$replaces = array('testa.testb.testc' => '1', 'testc.testa' => '2', 'testf' => '3');
$text = '{{$testa.testb.testc}}<br>{{$testc.testa}}<br>{{$testf}}<br>{{$aaaaa}}<br>';
preg_match_all('/\{\{\$([\w.]+)\}\}/', $text, $matches);
var_dump($matches[1]);
foreach($matches[1] as $match)
{
if(isset($replaces[$match]))
{
$text = str_replace('{{$'.$match.'}}', $replaces[$match], $text);
}
}
echo $text;
This works and returns :
1
2
3
{{$aaaaa}}
You don't need to use a regex for that since you are only dealing with fixed strings:
$replaces = array('testa.testb.testc' => 1, 'testc.testa' => 2, 'testf' => 3);
$keys = array_map(function ($item) {
return '{{$' . $item . '}}'; }, array_keys($replaces));
$trans = array_combine($keys, $replaces);
$result = strtr($text, $trans);
Note that array_map
is not needed if you write the replaces array like this:
$trans = array('{{$testa.testb.testc}}' => 1, '{{$testc.testa}}' => 2, '{{$testf}}' => 3);