访问preg_replace替换引用作为数组键


Accessing preg_replace replacement references as array keys

我有一个关联数组$dic,我想用$dic中相应的字符串替换HTML字符串中的href链接。

下面是我的代码:
$string = preg_replace("/<a href='"(.*?)'">(.*?)<'/a>/s", "$2->{$dic["$1"]}", $string);

上面的正则表达式没有按预期工作。但是在这种形式下它可以工作:

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

我想将<a>标签存储为LinkText->LinkFromDic

复杂表达式 {$dic["$1"]}中的"$1"被解释为文字字符串"$1",因为:

  • preg_replace替换之前处理复杂表达式
  • $1是一个无效的PHP变量名:

    有效的变量名以字母或下划线开头,后面跟着任意数量的字母、数字或下划线。

很容易验证:

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

string(10) "Dollar One"

旧的PHP版本支持e正则表达式修饰符,它允许将替换字符串作为PHP代码计算。但是它在PHP 5.5.0中被弃用,并在PHP 7.0.0中被删除。

然而,php_replace_callback函数足够灵活,可以解决这个问题:

$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);
输出

string(12) "Link->Page A"