gpt4 book ai didi

php - 关键字 highlight 是在 PHP preg_replace() 中高亮显示高亮

转载 作者:可可西里 更新时间:2023-10-31 23:49:53 25 4
gpt4 key购买 nike

我有一个小型搜索引擎在做它的事情,并且想要突出显示结果。我以为我已经解决了所有问题,直到我今天使用的一组关键字把它从水中吹了出来。

问题是 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;
}

最佳答案

我已经使用以下方法来解决这个问题:

<?php

$protected_matches = array();
function protect(&$matches) {
global $protected_matches;
return "\0" . array_push($protected_matches, $matches[0]) . "\0";
}
function restore(&$matches) {
global $protected_matches;
return '<span class="keywordHighlight">' .
$protected_matches[$matches[1] - 1] . '</span>';
}

preg_replace_callback('/\x0(\d+)\x0/', 'restore',
preg_replace_callback($patterns, 'protect', $target_string));

第一个 preg_replace_callback 取出所有匹配项并用空字节包裹的占位符替换它们;第二遍将它们替换为 span 标签。

编辑:忘记提及 $patterns 是按字符串长度从最长到最短排序的。

编辑;另一种解决方案

<?php
function highlightKeywords($data, $keywords = array(),
$prefix = '<span class="hilite">', $suffix = '</span>') {

$datacopy = strtolower($data);
$keywords = array_map('strtolower', $keywords);
$start = array();
$end = array();

foreach ($keywords as $keyword) {
$offset = 0;
$length = strlen($keyword);
while (($pos = strpos($datacopy, $keyword, $offset)) !== false) {
$start[] = $pos;
$end[] = $offset = $pos + $length;
}
}

if (!count($start)) return $data;

sort($start);
sort($end);

// Merge and sort start/end using negative values to identify endpoints
$zipper = array();
$i = 0;
$n = count($end);

while ($i < $n)
$zipper[] = count($start) && $start[0] <= $end[$i]
? array_shift($start)
: -$end[$i++];

// EXAMPLE:
// [ 9, 10, -14, -14, 81, 82, 86, -86, -86, -90, 99, -103 ]
// take 9, discard 10, take -14, take -14, create pair,
// take 81, discard 82, discard 86, take -86, take -86, take -90, create pair
// take 99, take -103, create pair
// result: [9,14], [81,90], [99,103]

// Generate non-overlapping start/end pairs
$a = array_shift($zipper);
$z = $x = null;
while ($x = array_shift($zipper)) {
if ($x < 0)
$z = $x;
else if ($z) {
$spans[] = array($a, -$z);
$a = $x;
$z = null;
}
}
$spans[] = array($a, -$z);

// Insert the prefix/suffix in the start/end locations
$n = count($spans);
while ($n--)
$data = substr($data, 0, $spans[$n][0])
. $prefix
. substr($data, $spans[$n][0], $spans[$n][1] - $spans[$n][0])
. $suffix
. substr($data, $spans[$n][1]);

return $data;
}

关于php - 关键字 highlight 是在 PHP preg_replace() 中高亮显示高亮,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9087471/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com