如何避免将 href 添加到字符串中的重叠关键字?

How can I avoid adding href to an overlapping keyword in string?

使用以下代码:

$text = "أطلقت غوغل النسخة المخصصة للأجهزة الذكية العاملة بنظام أندرويد من الإصدار “25″ لمتصفحها الشهير كروم.ولم تحدث غوغل تطبيق كروم للأجهزة العاملة بأندرويد منذ شهر تشرين الثاني العام الماضي، وهو المتصفح الذي يستخدمه نسبة 2.02% من أصحاب الأجهزة الذكية حسب دراسة سابقة. ";
$tags = "غوغل, غوغل النسخة, كروم";
$tags = explode(",", $tags);
foreach($tags as $k=>$v) {
    $text = preg_replace("/\b{$v}\b/u","<a href=\"index.php?s=news&tag=[=10=]\">[=10=]</a>",$text, 1);
}
echo $text;

将给出以下结果:

I <a href="index.php?s=news&tag=<a href="index.php?s=news&tag=love">love</a> <a href="index.php?s=news&tag=PHP">PHP</a>">love PHP</a>, but I am <a href="index.php?s=news&tag=facing">facing</a> a problem

请注意,我的文字是阿拉伯语。

与其多次调用 preg_replace,不如使用匹配任何标签的正则表达式调用一次:

$tags = explode(",", tags);
$tags_re = '/\b(' . implode('|', $tags) . ')\b/u';
$text = preg_replace($tags_re, '<a href="index.php?s=news&tag=[=10=]">[=10=]</a>', $text, 1);

这会将标签列表变成正则表达式 /\b(love|love php|facing)\b/ux|y 在正则表达式中表示匹配 xy.

方法是一次完成。这个想法是建立一个带有标签交替的模式。为了使这种方式工作,您必须在对标签进行排序之前,因为正则表达式引擎将在第一个成功的替代项处停止(否则 'love' 将始终匹配,即使它后面跟着 'php' 和 'love php' 永远不会匹配)。

要将替换限制为每个单词的第一次出现,您可以在找到标签后从数组中删除标签,并在替换回调函数中测试它是否始终存在于数组中:

$text = 'I love PHP, I love  love but I am facing a problem';
$tagsCSV = 'love, love php, facing';

$tags = explode(', ', $tagsCSV);

rsort($tags);

$tags = array_map('preg_quote', $tags);

$pattern = '/\b(?:' . implode('|', $tags) . ')\b/iu';

$text = preg_replace_callback($pattern, function ($m) use (&$tags) {
    $mLC = mb_strtolower($m[0], 'UTF-8');
    if (false === $key = array_search($mLC, $tags))
        return $m[0];

    unset($tags[$key]);
    return '<a href="index.php?s=news&tag=' . rawurlencode($mLC)
         . '">' . $m[0] . '</a>';
}, $text);

注意:构建url时必须对特殊字符进行编码,这就是为什么我使用preg_replace_callback而不是preg_replace才能使用[=14=的原因].

如果你必须处理一个utf8编码的字符串,你需要在模式中添加u修饰符并且你需要将strtolower替换为mb_strtolower)

preg_split方式

$tags = explode(', ', $tagsCSV);

rsort($tags);

$tags = array_map('preg_quote', $tags);

$pattern = '/\b(' . implode('|', $tags) . ')\b/iu';

$items = preg_split($pattern, $text, -1, PREG_SPLIT_DELIM_CAPTURE);

$itemsLength = count($items);
$i = 1;
while ($i<$itemsLength && count($tags)) {
    if (false !== $key = array_search(mb_strtolower($items[$i], 'UTF-8'), $tags)) {
        $items[$i] = '<a href="index.php?s=news&tag=' . rawurlencode($tags[$key])
                   . '">' . $items[$i] . '</a>';
        unset($tags[$key]);
    }
    $i+=2;
}

$result = implode('', $items);