Replacing variable placeholders with array elements (preg_replace)

Err, I’m trying to use a preg_replace to replace in a block of text, variable placeholders (of the form ‘[varname]’) with their corresponding values from an array - the array key is the variable name.



$code = "<h2>Foo is [foo] and bar is [bar].</h2>";

$a['foo'] = 'bar';
$a['bar'] = 'foo'

echo preg_replace("/\\[(\\S+)\\]/e", $a["\\$\\\\1"], $code);


That SHOULD output ‘<h2>Foo is bar and bar is foo.</h2>’ but it isn’t, it’s just showing ‘<h2>Foo is and bar is .</h2>’, which means the replacement’s not being made properly. Can anyone help, please? The preg functions rock but I hate 'em, heh.

Alex …

How about

$GLOBALS['a'] = array('foo'=>'bar', 'bar'=>'foo');
$subject = '<h2>Foo is [foo] and bar is [bar].</h2>';
$result = preg_replace_callback(
  '/\\[(\\S+?)\\]/'
  ,create_function('$matches', 'return @$GLOBALS["a"][$matches[1]];')
  ,$subject
  );


Isn’t there an easier way to do this? I got it working once, and lost the file. I’d rather not work with the globals… don’t mean to sound ungrateful though.

Call preg_replace in a loop, instead of all at once with the callback:

$a = array('foo'=>'bar', 'bar'=>'foo');
$result = '<h2>Foo is [foo] and bar is [bar].</h2>';
foreach(array_keys($a) as $key) {
  $result = preg_replace(
    '/\\['.preg_quote($key,'/').'\\]/'
    ,$a[$key]
    ,$result
    );
}

Yeah, that’d work too… But there’s a way of doing it, with one array, one string, and GAH! This is so frustrating. Thanks for your help man.


<?php
$string = '<h2>Foo is [foo] and bar is [bar].</h2>';
$replacements = array('foo' => 'bar', 'bar' => 'foo');

foreach($replacements AS $key => $value)
{
	$string = str_replace('['.$key.']', $value, $string);
}

echo $string;
?>

Maybe? Using preg_replace is a little over the top to do this.

Is str_replace faster in this case, then?

Im not sure if a loop with str_replace is faster then a single preg_replace. I know you can do array replacing all at once with one str_replace, but you’ll have to investigate on that yourself if you want more information on that.



echo preg_replace('/\\[(\\w+)\\]/e', '$a["\\\\1"]', $code);


Not 100% this would work: I don’t have access to a running version of PHP ATM.

Try this:

$string = ‘I am [foo] and [bar]’;
$needles = array(‘[foo]’, ‘[bar]’);
$replacements = array(‘foo_replacement’, ‘bar_replacement’);

str_replace($needles, $replacements, $string);

I use the same thing as feti suggests which works very well. Normally I run through the arraykeys and just add the { and } to them and put them one array and use array_values to put the values into another array and use str_replace like feti does. I recon this is quicker than preg_replace myself, but I haven’t benchmarked it. However, if this code is only used occasionally to render the odd error message, why should one care about this. If you are going to optimise for speed there will probably be many other areas in an app that could be optimised which can be highlighted using a profiler.

Here’s an example of using preg_replace from the excellent IS Layout [http://promoxy.mirrors.phpclasses.org/browse/package/1514.html] templating class:

/**
* Replace an Element of HTML Code
* @param string $Name Identification of element
* @param mixed $args String or Array of values passed in identification
* @param string $el HTML code for substitute the code between the element
* @access private
*/
function _Element_replace($Name, $args=NULL, $el=NULL)
{
if(is_array($args)){
$comp=“\s{1,}”;
foreach($args as $key=>$value)
$comp.=“$key=\”$value\“\s{0,}”;
}elseif($args!=NULL){
$comp=“\s{0,}”.$args;
$comp=preg_replace(“[\s{1,}]”,“\s{1,}”,$comp);
}

    $preg="|&lt;!-- $Name$comp(.*?)--&gt;(.*?)&lt;!-- end $Name --&gt;|s";
    $this-&gt;_code=preg_replace($preg,$el,$this-&gt;_code);
}

I use the method shown by feti and seconded by MiiJaySung. I haven’t found anything that produces faster template benchmarks.

Thank you fellas, for all your help. What’s infuriating is that I can get it to work with root-level variables, eg


$foo = 'foo';
$bar = 'bar';
$string = 'Foo is [foo] and bar is [bar]';
$string = preg_replace("/\\[(\\w+)\\]/e", "\\$\\\\1", $string);

And I can do it with array indices:


$a = array(0 => 'foo', 'bar');
$string = 'Foo is [0] and bar is [1]';
$string = preg_replace("/\\[(\\d+)\\]/",$a[(int) ${1}],$string);

But why can’t I do it with array keys?!

It’s nice str_replace decision.


  function & parse($string, $vars_ar) {
  	foreach($vars_ar as $k => $v) {
  		$search[] = '[' . $k . ']';
  		$replace[] = $v;
  	}
  	return str_replace($search, $replace, $string);
  }
  
  
  $string = '<h2>Foo is [foo] and bar is [bar].</h2>';
  $vars['foo'] = 'new_foo';
  $vars['bar'] = 'new_bar';
  
  echo parse($string, $vars);

Copy-pasted directly from my own application:

$querySet->query_string = preg_replace( '/\\{(\\w+)\\}/e', "\\$query_data['\\\\1']", $query_string );

This works just fine in PHP5, and it should work in PHP4.

So the next line should work for you, unless you’re running some ancient version of PHP…

$string = preg_replace( '/\\[(\\w+)\\]/e', "\\$a['\\\\1']", $string );

$string = preg_replace('~\\[\\w+\\]~e', '@$a$0', $string)

:wink:

Azmo and Stereofrog, THANK YOU. Finally.

:slight_smile:

The keyword here is template-engine.
If you need one - pick a package instead of reinventing the wheel. (smarty seems to be a popular choice - more lightweight alternatives exist, such as [url=http://www.php-tools.de/site.php?file=patTemplate/overview.xml]patTemplate). In fact you may not need one though - discover PHP as it’s own template-engine with such tools as [url=http://phpsavant.com/]PHPSavant or [url=http://simplet.sourceforge.net/]SimpleT