DelightedD0D DelightedD0D - 1 month ago 12
PHP Question

Avoid backreference replacement in php's preg_replace

Consider the below use of

preg_replace


$str='{{description}}';
$repValue='$0.0 $00.00 $000.000 $1.1 $11.11 $111.111';

$field = 'description';
$pattern = '/{{'.$field.'}}/';

$str =preg_replace($pattern, $repValue, $str );
echo $str;


// Expected output: $0.0 $00.00 $000.000 $1.1 $11.11 $111.11
// Actual output: {{description}}.0 {{description}}.00 {{description}}0.000 .1 .11 1.111


Here is a phpFiddle showing the issue



It's clear to me that the actual output is not as expected because
preg_replace
is viewing
$0, $0, $0, $1, $11, and $11
as back references for matched groups replacing
$0
with the full match and
$1 and $11
with an empty string since there are no capture groups 1 or 11.

How can I prevent
preg_replace
from treating prices in my replacement value as back references and attempting to fill them?

Note that
$repValue
is dynamic and it's content will not be know before the operation.

Answer

Escape the dollar character before using a character translation (strtr):

$repValue = strtr('$0.0 $00.00 $000.000 $1.1 $11.11 $111.111', ['$'=>'\$']);

For more complicated cases (with dollars and escaped dollars) you can do this kind of substitution (totally waterproof this time):

$str = strtr($str, ['%'=>'%%', '$'=>'$%', '\\'=>'\\%']);
$repValue = strtr($repValue, ['%'=>'%%', '$'=>'$%', '\\'=>'\\%']);
$pattern = '{{' . strtr($field, ['%'=>'%%', '$'=>'$%', '\\'=>'\\%']) . '}}';
$str = preg_replace($pattern, $repValue, $str );
echo strtr($str, ['%%'=>'%', '$%'=>'$', '\\%'=>'\\']);