【发布时间】:2012-02-23 15:21:50
【问题描述】:
我有一个小型搜索引擎在做它的事情,并且想要突出显示结果。我以为我已经解决了所有问题,直到我今天使用的一组关键字将其从水中吹走。
问题是 preg_replace() 正在循环替换,后来的替换正在替换我插入到以前的文本中的文本。使困惑?这是我的伪函数:
public function highlightKeywords ($data, $keywords = array()) {
$find = array();
$replace = array();
$begin = "<span class=\"keywordHighlight\">";
$end = "</span>";
foreach ($keywords as $kw) {
$find[] = '/' . str_replace("/", "\/", $kw) . '/iu';
$replace[] = $begin . "\$0" . $end;
}
return preg_replace($find, $replace, $data);
}
好的,所以它在搜索“fred”和“dagg”时有效,但遗憾的是,在搜索“class”和“lass”和“as”时,突出显示“Joseph's Class Group”时会遇到真正的问题
Joseph's <span class="keywordHighlight">Cl</span><span <span c<span <span class="keywordHighlight">cl</span>ass="keywordHighlight">lass</span>="keywordHighlight">c<span <span class="keywordHighlight">cl</span>ass="keywordHighlight">lass</span></span>="keywordHighlight">ass</span> Group
我怎样才能让后面的替换只适用于非 HTML 组件,但也允许标记整个匹配?例如如果我正在搜索“cla”和“lass”,我希望“class”全部突出显示,因为两个搜索词都在其中,即使它们重叠,并且应用于第一个匹配项的突出显示具有“class” ",但那不应突出显示。
叹息。
我宁愿使用 PHP 解决方案,也不愿使用 jQuery(或任何客户端)解决方案。
注意:我尝试按长度对关键字进行排序,先做长的,但这意味着交叉搜索不会突出显示,这意味着“cla”和“lass”只是单词“class”的一部分会突出显示,它仍然谋杀了替换标签:(
编辑:我已经搞砸了,从铅笔和纸开始,开始胡言乱语,然后想出了一些非常乏味的代码来解决这个问题。这不是很好,因此仍然非常感谢您提出建议来调整/加快速度:)
public function highlightKeywords ($data, $keywords = array()) {
$find = array();
$replace = array();
$begin = "<span class=\"keywordHighlight\">";
$end = "</span>";
$hits = array();
foreach ($keywords as $kw) {
$offset = 0;
while (($pos = stripos($data, $kw, $offset)) !== false) {
$hits[] = array($pos, $pos + strlen($kw));
$offset = $pos + 1;
}
}
if ($hits) {
usort($hits, function($a, $b) {
if ($a[0] == $b[0]) {
return 0;
}
return ($a[0] < $b[0]) ? -1 : 1;
});
$thisthat = array(0 => $begin, 1 => $end);
for ($i = 0; $i < count($hits); $i++) {
foreach ($thisthat as $key => $val) {
$pos = $hits[$i][$key];
$data = substr($data, 0, $pos) . $val . substr($data, $pos);
for ($j = 0; $j < count($hits); $j++) {
if ($hits[$j][0] >= $pos) {
$hits[$j][0] += strlen($val);
}
if ($hits[$j][1] >= $pos) {
$hits[$j][1] += strlen($val);
}
}
}
}
}
return $data;
}
【问题讨论】:
-
$hits[$i][0]表示给出了 0$hits?哦,我的这个想法…… -
$hits[$i][0]是关键字的起点,$hits[$i][1]是终点。它在纸上不那么令人困惑:) -
再读一遍我的,在精神上用
S替换$......恐怕只是个坏笑话
标签: php regex preg-replace highlight keyword