突出显示给定字符串中的多个匹配项

时间:2014-09-18 15:42:29

标签: php regex

我在PHP中使用此功能,用于突出显示给定字符串中的搜索词:

 function highlight_match($h, $text_to_search){ 
    foreach($h as $pattern){
        $text_to_search = preg_replace("/($pattern)/i", "<span class=\"highlight_match\">$1</span>", $text_to_search);
    }
    return $text_to_search;
 }    

使用这样的功能可以正常工作:

 $h = array(
     'peter',
     'bell'
 );
 $text_to_search = 'peter pan likes tinker bell'
 echo highlight_match($h, $text_to_search);
 // results: <span class="highlight_match">peter</span> pan likes tinker <span class="highlight_match">bell</span>

当搜索项包含上一次迭代中刚刚替换(添加)的部分内容时,就会出现问题,如下例所示:

 $h = array(
     'pan',
     'bell'
 );
 $text_to_search = 'peter pan likes tinker bell'
 echo highlight_match($h, $text_to_search);
 // results: peter <s<span class="highlight_match">pan</span> class="highlight_match">pan</s<span class="highlight_match">pan</span>> likes tinker <span class="highlight_match">bell</span>

这是因为该函数正在迭代要查找的术语列表,因此第二个+迭代可以具有&lt; span class =“highlight_match”&gt; ..&lt; / span&gt;如果当前迭代的搜索项匹配给定字符串中的任何内容(包括我们刚刚在上一次迭代中添加的任何文本/ html),它将被替换。

我不确定如何解决这个问题。是否有功能/方法一次完成字符串上的所有不同匹配/替换?

1 个答案:

答案 0 :(得分:2)

您可以将所有字符串放入一个模式中:

$highlighted = preg_replace(
    "/(peter|pan)/i", 
    "<span class=\"highlight_match\">$1</span>",
    $text_to_search);

在这种情况下,模式(peter|pan)表示“ peter pan ”。

还有另一种解决方案比简单的 OR 模式更灵活。如果你真的需要一个接一个地应用你的替代品,它就有效。

它分两步完成:首先你像以前一样替换文本,但是你不插入<span>,而是一个永远不会匹配你的模式的占位符。在第二步中,将占位符替换为实际的突出显示标记:

$replace = array('pan', 'bell');
$text_to_search = 'peter pan likes tinker bell';

$delim = 'yB9oMjDWpMy'; // just a random string; must not match your patterns
$tags = array(
    "open_$delim" => '<span class="highlight">',
    "close_$delim" => '</span>'
);

foreach ($replace as $term)
{
    $text_to_search = preg_replace(
        "/($term)/i",
        sprintf('open_%1$s$1close_%1$s' , $delim),
        $text_to_search);
}

// intermediate result:
// peter open_yB9oMjDWpMypanclose_yB9oMjDWpMy likes tinker open_yB9oMjDWpMybellclose_yB9oMjDWpMypeter pan likes tinker bell

$text_to_search = str_replace(
    array_keys($tags),
    array_values($tags),
    $text_to_search);

// final result
// peter <span class="highlight">pan</span> likes tinker <span class="highlight">bell</span>

这有点复杂,但它允许使用更多种类的正则表达式模式。