Replace curly braced placeholders with values from a lookup array
Asked Answered
R

4

7

I would like to know if there is a simple way to use the matched pattern in a preg_replace as an index for the replacement value array.

e.g.

preg_replace("/\{[a-z_]*\}/i", "{$data_array[\1]}", $string);

Search for a placeholder like {xxx} and replace it with the value in $data_array['xxx'], where xxx is the matched text inside the curly braces.

But this expression does not work as it's invalid php.

I have written the following function, but I'd like to know if it is possible to do it simply. I could use a callback, but how would I pass the $data_array to it too?

function mailmerge($string, $data_array, $tags='{}')
{
    $tag_start=$tags[0];
    $tag_end  =$tags[1];
    if( (!stristr($string, $tag_start)) && (!stristr($string, $tag_end)) ) return $string;
    
    while(list($key,$value)=each($data_array))
    {
        $patterns[$key]="/".preg_quote($tag_start.$key.$tag_end)."/";
    }
    ksort($patterns);
    ksort($data_array);

    return preg_replace($patterns, $data_array, $string);
}
Randolphrandom answered 26/4, 2013 at 13:37 Comment(3)
Use preg_replace_callback()Innervate
In this case (you already filter the input data) you could have used the /e modifier (your curly string expression needed array key quotes still). It's outlawed now however, and has limited advantages over p_r_callback. Take care that you also need paranthesis for a capture group /\{([a-z_]*)\}/i.Fonda
Cheers HamZa. I knew about preg_replace_callback(), just wasn't sure how to pass it the data array. (in the question)Randolphrandom
I
10

From my head:

preg_replace_callback("/\{([a-z_]*)\}/i", function($m) use($data_array){
  return $data_array[$m[1]];
}, $string);

Note: The above function requires PHP 5.3+.

Innervate answered 26/4, 2013 at 13:41 Comment(1)
Cheers - had to change it slightly \{([a-z_]*)\} and $data_array[$m[1]];Randolphrandom
T
1

Associative Array replacement - keep matched fragments if not found:

$words=array("_saudation_"=>"Hello", "_animal_"=>"cat", "_animal_sound_"=>"MEooow");

$source=" _saudation_! My Animal is a _animal_ and it says _animal_sound_ ,  _no_match_";

echo (preg_replace_callback("/\b_(\w*)_\b/", function($match) use ($words) { if(isset($words[$match[0]])){
return ($words[$match[0]]);}else{
return($match[0]);} 
},  $source));

    //returns:  Hello! My Animal is a cat and it says MEooow ,  _no_match_

*Notice, thats although "_no_match_" lacks translation, it will match during regex, but preserve its key.

Thud answered 3/5, 2014 at 0:17 Comment(1)
This is an improvement to @Hamza solution since it would break if no index was found for a particular matchThud
T
1

From PHP7.4, arrow syntax is the most concise syntax for this preg_replace_callback() task. It doesn't make sense to match a zero-length substring between two curly braces, so I'll use + as a one or more quantifier.

If the matched substring is not found as a key in the lookup array, reinsert the full string match so that the placeholder appears unchanged.

Code: (Demo)

$string = 'try replacing {foo} and {huh} and {bar} in text';

$data_array = [
    'foo' => 'fighters',
    'bar' => 'snacks',
];

echo preg_replace_callback(
         '/{(\w+)}/',
         fn($m) => $data_array[$m[1]] ?? $m[0],
         $string
     );

Output:

try replacing fighters and {huh} and snacks in text
Turnout answered 5/11, 2023 at 11:42 Comment(0)
C
-1

you can use preg_replace_callback and write a function where you can use that array index, or else you can use the e modifier to evaluate the replacement string (though note that the e modifier is deprecated, so the callback function is better solution).

Cheder answered 26/4, 2013 at 13:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.