【问题标题】:Automatically add links to strings of keywords自动添加指向关键字字符串的链接
【发布时间】:2019-03-27 08:58:30
【问题描述】:

在我的文章中,我想自动添加指向关键字的链接。 我的关键字数组:

 $keywords = [
       0=>['id'=>1,'slug'=>'getName','url'=>'https://example.com/1'],
       1=>['id'=>2,'slug'=>'testName','url'=>'https://example.com/2'],
       2=>['id'=>3,'slug'=>'ign','url'=>'https://example.com/3'],
    ];

这是我的代码:

private function keywords_replace(string $string, array $key_array)
{
    $array_first = $key_array;
    $array_last = [];
    foreach ($array_first as $key=>$value)
    {
        $array_last[$key] = [$key, $value['slug'], '<a target="_blank" href="' . $value['url'] . '" title="' . $value['slug'] . '">' . $value['slug'] . '</a>'];
    }
    $count = count($array_last);
    for ($i=0; $i<$count;$i++)
    {
        for ($j=$count-1;$j>$i;$j--)
        {
            if (strlen($array_last[$j][1]) > strlen($array_last[$j-1][1]))
            {
                $tmp = $array_last[$j];
                $array_last[$j] = $array_last[$j-1];
                $array_last[$j-1] = $tmp;
            }
        }
    }
    $keys = $array_last;
    foreach ($keys as $key)
    {
        $string = str_ireplace($key[1],$key[0],$string);
    }
    foreach ($keys as $key)
    {
        $string = str_ireplace($key[0],$key[2],$string);
    }
    return $string;
}

结果:

 $str = "<p>Just a test: getName  testName";
 echo $this->keywords_replace($str,$keywords);

这样:只是测试:getNametestName
非常重要:如果字符串没有空格,则不匹配。因为我会使用其他语言,句子不会有空格像英语。喜欢 Wordpress 关键词自动链接

我觉得我的代码并不完美,有没有更好的算法来实现这个功能?谢谢!

【问题讨论】:

  • 显示您期望的数组示例
  • 我在输出后添加了效果。
  • 你的蛞蝓大多是驼峰式,还是你关心不区分大小写?
  • 我不关心小写和驼峰的大小写。

标签: php arrays algorithm


【解决方案1】:

首先,您需要使用循环将数组的结构更改为键/值,结果存储在$newKeywords 中。然后使用preg_replace_callback() 选择字符串中的每个单词并检查它是否存在于数组的键中。如果存在,将其包装在锚标记中。

$newKeywords = [];
foreach ($keywords as $keyword)
    $newKeywords[$keyword['slug']] = $keyword['url'];

$newStr = preg_replace_callback("/(\w+)/", function($m) use($newKeywords){
    return isset($newKeywords[$m[0]]) ? "<a href='{$newKeywords[$m[0]]}'>{$m[0]}</a>" : $m[0];
}, $str);

输出:

<p>Just a test: <a href='https://www.getname.com'>getName</a>  <a href='https://www.testname.com'>testName</a></p>

demo查看结果

【讨论】:

  • 非常感谢,第一次看到preg_replace_callback函数。
  • 如果字符串没有空格,则不匹配。因为我会使用其他语言,句子不会像英文那样有空格。
【解决方案2】:

您可以使用array_reducepreg_replace 将字符串中出现的所有slug 单词替换为相应的url 值:

$keywords = [
       0=>['id'=>1,'slug'=>'getName','url'=>'https://www.getname.com'],
       1=>['id'=>2,'slug'=>'testName','url'=>'https://www.testname.com'],
       2=>['id'=>3,'slug'=>'ign','url'=>'https://www.ign.com'],
    ];
$str = "<p>Just a test: getName  testName";
echo array_reduce($keywords, function ($c, $v) { return preg_replace('/\\b(' . $v['slug'] . ')\\b/', $v['url'], $c); }, $str);

输出:

<p>Just a test: https://www.getname.com https://www.testname.com

Demo on 3v4l.org

更新

要将文本变成链接,你需要使用这个:

echo array_reduce($keywords, 
                  function ($c, $v) { 
                     return preg_replace('/\\b(' . $v['slug'] . ')\\b/',
                                         '<a href="'. $v['url'] . '">$1</a>', $c);
                  }, 
                  $str);

输出:

<p>Just a test: <a href="https://www.getname.com">getName</a> <a href="https://www.testname.com">testName</a>

Updated demo

更新 2

由于某些被替换的链接包含的单词也是slug 的值,因此有必要使用strtr 的数组格式一次完成所有替换。我们使用array_columnarray_combinearray_map 构建一组模式和替换,然后将其传递给strtr

$reps = array_combine(array_column($keywords, 'slug'),
                      array_map(function ($k) { return '<a href="' . $k['url'] .'">' . $k['slug'] . '</a>'; }, $keywords
                      ));
$newstr = strtr($str, $reps);

New demo

【讨论】:

  • 关键字不替换为url,改为
  • @DomainRocker 对不起,我误解了你的问题。我想我现在有你想要的了。
  • 如果字符串没有空格,则不匹配。因为我会使用其他语言,句子不会像英文那样有空格。
  • @DomainRocker 您可以从正则表达式中删除 \\b ,这将阻止它寻找空格。请注意,如果您有 unicode 字符,您可能还需要对正则表达式使用 u 修饰符。如果您可以使用其他示例文本编辑您的问题,我很乐意编辑我的答案以满足这些要求。
  • @DomainRocker 我添加了基于您的新更新和演示。它适用于您的示例数据。
【解决方案3】:

我的答案使用 preg_replace 和上面的Nick's

它依赖于模式和替换是大小相等的数组,具有相应的模式和替换。

需要尊重单词边界,我怀疑你可以通过简单的字符串替换来做到这一点。

<?php
$keywords = [
    0=>['id'=>1,'slug'=>'foo','url'=>'https://www.example.com/foo'],
    1=>['id'=>2,'slug'=>'bar','url'=>'https://www.example.com/bar'],
    2=>['id'=>3,'slug'=>'baz','url'=>'https://www.example.com/baz'],
];

foreach ($keywords as $item)
{
    $patterns[]     = '@\b(' . $item['slug'] . ')\b@i';
    $replacements[] = '<a href="' . $item['url'] . '">$1</a>';
}

$html = "<p>I once knew a barbed man named <i>Foo</i>, he often visited the bar.</p>";

print preg_replace($patterns, $replacements, $html);

输出:

<p>I once knew a barbed man named <i><a href="https://www.example.com/foo">Foo</a></i>, he often visited the <a href="https://www.example.com/bar">bar</a>.</p>

【讨论】:

  • 如果您不想替换所有出现的 slug,您可以使用 preg_replace 上的第四个参数为 1,这样您就不会被链接淹没。
  • 如果字符串没有空格,则不匹配。因为我会使用其他语言,句子不会像英文那样有空格
  • @DomainRocker,但您的示例字符串有空格。
  • @DomainRocker,对于您的示例 ign 问题,如果您没有单词边界,例如空格,会发生什么?如果说我有这个词:ignominious?
  • 我的意思是在其他语言的情况下,例如中文,句子中没有空格。所以我无法匹配关键字。
【解决方案4】:

这是我的回答:感谢@Nick

$content = array_reduce($keywords , function ($c, $v) {
    return preg_replace('/(>[^<>]*?)(' . $v['slug'] . ')([^<>]*?<)/', '$1<a href="'. $v['url'] . '">$2</a>$3', $c);
}, $str);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-01
    • 2012-05-06
    • 1970-01-01
    • 2011-01-30
    相关资源
    最近更新 更多