s4y
s4y

Reputation: 51715

Replacing tokens in a string from an array

Let's say I have a string

This $0 is $2 $1. Still, \$$3 is a lot to pay for a puppy.

and an array of replacements

array('puppy', 'cute', 'ridiculously', '1300')

What would be the cleanest way to replace the tokens in the string with the corresponding items in the array, letting me backslash-escape the token character (in this case $)? I also want to replace unmatched tokens with the empty string.

Upvotes: 1

Views: 5825

Answers (5)

Tramov
Tramov

Reputation: 1186

This solution follows the question and borrows a little from Josh Leitzel's answer. Unmatched patterns (eg. $4, $5) are replaced by an empty string, removing them from the input.

$input = "This $0 is $2 $1. Still, \$$3 is a lot to pay for a puppy.";
$replacements = array('puppy','cute','ridiculously','1300');
$pattern = "/[$]{1}([0-9]{1})/";

preg_match_all($pattern, $input, $matches);

if (isset($matches[1]))
 foreach ($matches[1] as $key => $value)
 {
  $input = str_replace("$".$value, $replacements[$value], $input);
 }

echo $input;

Output:

This puppy is ridiculously cute. Still, $1300 is a lot to pay for a puppy.

Upvotes: 0

user187291
user187291

Reputation: 53940

i guess you meant "\$3", not "\$$3"

preg_replace('~(?<!\\\\)\$(\d+)~e', 'isset($array[$1])?$array[$1]:""', $source);

btw, did you know that sprintf allows numbered params as well (http://php.net/manual/en/function.sprintf.php example 3)

Upvotes: 1

cletus
cletus

Reputation: 625237

Here's one version.

$replacements = array('puppy', 'cute', 'ridiculously', '1300');
$input = 'This $0 is $2 $1. Still, \$3 is a lot to pay for a puppy.';

$output = preg_replace_callback('/(?<!\\\\)\$(\d+)/', 'replace_input', $input);

echo $input . "<br>";
echo $output;

function replace_input($matches) {
  global $replacements;
  $index = $matches[1];
  return $index < 0 || $index >= count($replacements) ? $matches[0] : $replacements[$index];
}

Output:

This $0 is $2 $1. Still, \$3 is a lot to pay for a puppy.
This puppy is ridiculously cute. Still, \$3 is a lot to pay for a puppy.

It handles a backslash before the $ to escape that variable. That could be an awkward syntax because then you need to escape backslashes, which complicates it further (and isn't handled in this case). The regular expression basically means $ followed by one or more digits as long as the $ isn't preceded by a backslash (using a negative lookbehind).

It uses a global for the replacements array. There are two alternatives to this:

  1. Use a closure (requires PHP 5.3+); or
  2. Use create_function().

But I think the global is simpler and "global" unless you have a good reason to do something different in spite of the usual distaste we have for such things.

Upvotes: 1

Kon Pal
Kon Pal

Reputation: 574

$test_sub= 'This $0 is $2 $1. Still, \$$3 is a lot to pay for a puppy.';
$GLOBALS['replacers'] = array('puppy', 'cute', 'ridiculously', '1300');
echo preg_replace_callback('/[^\$]\$([0-9])+/',
    create_function(
        '$matches',
        'return $matches[0][0] . $GLOBALS[\'replacers\'][$matches[1]];'
    ),
    $test_sub
);

This is a POC of how it can be done. A simple regular expression and a callback for replacement. The actual implementation varies on what exactly you want to do with it. I hope it helped.

Upvotes: 1

Josh Leitzel
Josh Leitzel

Reputation: 15209

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

Upvotes: 4

Related Questions