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);
}
3
  • 2
    Use preg_replace_callback() Commented Apr 26, 2013 at 13:38
  • 1
    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. Commented Apr 26, 2013 at 13:50
  • 1
    Cheers HamZa. I knew about preg_replace_callback(), just wasn't sure how to pass it the data array. (in the question) Commented Apr 26, 2013 at 14:09

4 Answers 4

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+.

Sign up to request clarification or add additional context in comments.

1 Comment

Cheers - had to change it slightly \{([a-z_]*)\} and $data_array[$m[1]];
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.

1 Comment

This is an improvement to @Hamza solution since it would break if no index was found for a particular match
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

Comments

-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).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.