如何避免将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=$0'">$0</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

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

方法是一次完成所有操作。其想法是用交替的标记构建一个模式。要使这种方式发挥作用,您必须在对标记进行排序之前,因为正则表达式引擎将在第一个成功的替换项处停止(否则,即使后面跟着"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才能使用rawurlencode的原因。

如果必须处理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);

与其多次调用preg_replace,不如使用匹配任何标记的regexp一次性调用它:

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

这将标记列表转换为正则表达式/'b(love|love php|facing)'b/u。正则表达式中的x|y表示匹配xy