将正则表达式匹配测试添加到字符串中的所有链接

Prepending regex matched test to all links in a string

假设我有一个像这样的字符串 $str:

aaa
<a href="link.php?x=banana">text 1</a>
bbb
<a href="different_url.php">text 2</a>
ccc
<a href="link.php?x=orange">text 3</a>
ddd

我想让所有包含 link.php 的链接都在前面加上 x 值,例如:

aaa
banana <a href="link.php?x=banana">text 1</a>
bbb
<a href="different_url.php">text 2</a>
ccc
orange <a href="link.php?x=orange">text 3</a>
ddd

我正在尝试使用 preg_replace 执行此操作,但我似乎无法正确构建我的正则表达式:

$str = preg_replace('/<a (.*?)link.php(.*?)<\/a>/', ' <a link.php<\/a>', $str);

这当然不行。我有点不知道如何构建它,因为我希望它包含整个原始字符串以及一个子集。

最简单的方法是什么?为了将来参考,这种操作甚至叫什么?

这是一种使用 DOMDocument 来实现的方法。您可以使用 DOMNode::insertBefore 方法轻松地在节点之前插入内容。

$html = <<<'EOD'
aaa
<a href="link.php?x=banana">text 1</a>
bbb
<a href="different_url.php">text 2</a>
ccc
<a href="link.php?x=orange">text 3</a>
ddd
EOD;

$dom = new DOMDocument;
$dom->loadHTML('<div id="root">' . $html . '</div>');
$nodeList = $dom->getElementsByTagName('a');

foreach($nodeList as $link) {
    $query = parse_url($link->getAttribute('href'), PHP_URL_QUERY);
    if ( !$query ) continue;
    parse_str($query, $arr);
    if ( isset($arr['x']) )
        $link->parentNode->insertBefore($dom->createTextNode($arr['x'] . ' '), $link);
}

$result = '';

foreach($dom->getElementById('root')->childNodes as $childNode) {
    $result .= $dom->saveHTML($childNode);
}

echo $result;

demo

DOMDocument 需要根元素才能构建 DOM 树。由于您正在处理 html 文档的一部分而不是整个 html 文档,因此您需要添加一个虚拟根元素 <div id="root">...</div> 并在最后提取该文档的所有子元素根元素。