Saeed Jassani Saeed Jassani - 1 month ago 13
PHP Question

Accessing preg_replace replacement references as array keys

I have an associative array

$dic
, and I want to replace the
href
link in an HTML string with the corresponding string in
$dic
.

Here is my code:

$string = preg_replace("/<a href=\"(.*?)\">(.*?)<\/a>/s", "$2->{$dic["$1"]}", $string);


The above regular expression doesn't work as intended. But in this form it works:

$string = preg_replace("/<a href=\"(.*?)\">(.*?)<\/a>/s", "$2->$1", $string);


I want to store the
<a>
tags as
LinkText->LinkFromDic
.

Answer

The "$1" within the complex expression {$dic["$1"]} is interpreted as literal string "$1", because:

  • the complex expression is processed before the preg_replace replacement references are applied;
  • $1 is an invalid variable name in PHP:

    A valid variable name starts with a letter or underscore, followed by any number of letters, numbers, or underscores.

It is easy to verify that:

$dic = ['$1' => 'Dollar One'];
var_dump("{$dic["$1"]}");

Output

string(10) "Dollar One"

Older PHP versions supported e regular expression modifier, which allowed to evaluate the replacement string as PHP code. But it was deprecated in PHP 5.5.0, and removed as of PHP 7.0.0.

However, php_replace_callback function is flexible enough to fix the problem:

$dic = ['/page/a' => 'Page A'];

$string = <<<'EOHTML'
<a href="/page/a">Link</a>
EOHTML;

$string = preg_replace_callback('/<a href\="(.*?)">(.*?)<\/a>/s',
  function ($matches) use ($dic) {
    $v = isset($dic[$matches[1]]) ? $dic[$matches[1]] : $matches[1];
  return count($matches == 3) ? "{$matches[2]}->$v" : $matches[0];
}, $string);

var_dump($string);

Output

string(12) "Link->Page A"