【问题标题】:With preg_match it's possible to have the same pattern and have different replacements? [duplicate]使用 preg_match 可以有相同的模式并有不同的替换? [复制]
【发布时间】:2019-09-03 23:56:30
【问题描述】:

我创建了这个模式

$pattern = "/<a href='(?<href>.+?)'>(?<name>.+?)<\/a>/i";

我有这个例子,

$string = "<a href='https://www.php.net/'>https://www.php.net/</a> 
<a href='https://stackoverflow.com/'>https://stackoverflow.com/</a> 
<a href='https://www.google.com/'>https://www.google.com/</a>";

使用它,我可以找到匹配项并提取 href 和名称。

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

Array
(
    [0] => Array
        (
            [0] => https://www.php.net/
            [1] => https://stackoverflow.com/
            [2] => https://www.google.com/
        )

    [href] => Array
        (
            [0] => https://www.php.net/
            [1] => https://stackoverflow.com/
            [2] => https://www.google.com/
        )

    [1] => Array
        (
            [0] => https://www.php.net/
            [1] => https://stackoverflow.com/
            [2] => https://www.google.com/
        )

    [name] => Array
        (
            [0] => https://www.php.net/
            [1] => https://stackoverflow.com/
            [2] => https://www.google.com/
        )

    [2] => Array
        (
            [0] => https://www.php.net/
            [1] => https://stackoverflow.com/
            [2] => https://www.google.com/
        )

)

问题是当我使用 preg_replace 时,由于模式相同,它会更改所有 URL 的相同信息,我只需要更改名称并相应地保留其余信息。

使用,

if(preg_match_all($pattern, $string, $matches))
{
    $string = preg_replace($pattern, "<a href='$1'>Name</a>", $string);

}

我可以从组中获取结果,并保留 href 的第一部分。但是,如果我尝试更改名称,所有结果都是一样的。

如果我尝试使用“str_replace”,我可以得到不同的结果,但这给了我 2 个问题。一是如果我尝试替换名称,我也会更改href,如果我有类似的带有“更多斜线”的URL,它将更改匹配部分,并保留其余信息。

在数据库中,我有一个包含名称列的 URL 列表,如果字符串与表中的任何行匹配,我需要相应地更改名称并保留 href。

有什么帮助吗?

谢谢。

亲切的问候!

【问题讨论】:

标签: php regex preg-replace preg-match str-replace


【解决方案1】:

我假设您使用如下格式从数据库中检索行:

$rows = [
  ['href' => 'https://www.php.net/', 'name' => 'PHP.net'],
  ['href' => 'https://stackoverflow.com/', 'name' => 'Stack Overflow'],
  ['href' => 'https://www.google.com/', 'name' => 'Google']
];

从那里,您可以首先使用循环或array_reduce 创建一个 href -> 名称映射:

$rows_by_href = array_reduce($rows, function ($rows_by_href, $row) {
  $rows_by_href[$row['href']] = $row['name'];
  return $rows_by_href;
}, []);

然后您可以使用preg_replace_callback 将每个匹配项替换为其关联的名称(如果存在):

$result = preg_replace_callback($pattern, function ($matches) use ($rows_by_href) {
  return "<a href='" . $matches['href'] . "'>" 
    . ($rows_by_href[$matches['href']] ?? $matches['name']) 
    . "</a>";
}, $string);

echo $result;

演示:https://3v4l.org/IY6p0

请注意,这假定$string 中的 URL(href)的格式与来自您的数据库的格式完全相同。否则,您可以rtrim 尾部斜杠或事先做任何您需要的事情。

另外请注意,如果可以避免的话,使用正则表达式解析 HTML 通常是个坏主意。 DOM 解析器更合适,除非您必须解析来自评论或论坛帖子或不受您控制的东西的字符串。

【讨论】:

  • 不知道 preg_replace_callback。感谢您的帮助。
猜你喜欢
  • 2022-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-27
  • 2020-10-19
相关资源
最近更新 更多