当前位置: 首页 > 面试题库 >

突出显示段落中的关键字

林承悦
2023-03-14
问题内容

我需要在段落中突出显示关键字,就像google在其搜索结果中一样。假设我有一个带有博客文章的MySQL数据库。当用户搜索某个关键字时,我希望返回包含这些关键字的帖子,但只显示帖子的一部分(包含搜索关键字的段落)并突出显示那些关键字。

我的计划是这样的:

  • 找到内容中包含搜索关键字的帖子ID;
  • 再次阅读该帖子的内容,并将每个单词放入固定的缓冲区数组(50个单词)中,直到找到关键字。

您能为我提供一些逻辑上的帮助吗,或者至少可以告诉我我的逻辑是否可以?我正在学习PHP。


问题答案:

如果它包含html(请注意,这是一个非常强大的解决方案):

$string = '<p>foo<b>bar</b></p>';
$keyword = 'foo';
$dom = new DomDocument();
$dom->loadHtml($string);
$xpath = new DomXpath($dom);
$elements = $xpath->query('//*[contains(.,"'.$keyword.'")]');
foreach ($elements as $element) {
    foreach ($element->childNodes as $child) {
        if (!$child instanceof DomText) continue;
        $fragment = $dom->createDocumentFragment();
        $text = $child->textContent;
        $stubs = array();
        while (($pos = stripos($text, $keyword)) !== false) {
            $fragment->appendChild(new DomText(substr($text, 0, $pos)));
            $word = substr($text, $pos, strlen($keyword));
            $highlight = $dom->createElement('span');
            $highlight->appendChild(new DomText($word));
            $highlight->setAttribute('class', 'highlight');
            $fragment->appendChild($highlight);
            $text = substr($text, $pos + strlen($keyword));
        }
        if (!empty($text)) $fragment->appendChild(new DomText($text));
        $element->replaceChild($fragment, $child);
    }
}
$string = $dom->saveXml($dom->getElementsByTagName('body')->item(0)->firstChild);

结果是:

<p><span class="highlight">foo</span><b>bar</b></p>

与:

$string = '<body><p>foobarbaz<b>bar</b></p></body>';
$keyword = 'bar';

您得到(为了便于阅读,分为多行):

<p>foo
    <span class="highlight">bar</span>
    baz
    <b>
        <span class="highlight">bar</span>
    </b>
</p>

提防非dom解决方案(如regexstr_replace),因为突出显示诸如“
div”之类的东西有完全破坏HTML的趋势……这只会在正文中“突出显示”字符串,而不会在标签内……

编辑 由于需要Google样式的结果,因此这是一种处理方法:

function getKeywordStubs($string, array $keywords, $maxStubSize = 10) {
    $dom = new DomDocument();
    $dom->loadHtml($string);
    $xpath = new DomXpath($dom);
    $results = array();
    $maxStubHalf = ceil($maxStubSize / 2);
    foreach ($keywords as $keyword) {
        $elements = $xpath->query('//*[contains(.,"'.$keyword.'")]');
        $replace = '<span class="highlight">'.$keyword.'</span>';
        foreach ($elements as $element) {
            $stub = $element->textContent;
            $regex = '#^.*?((\w*\W*){'.
                 $maxStubHalf.'})('.
                 preg_quote($keyword, '#').
                 ')((\w*\W*){'.
                 $maxStubHalf.'}).*?$#ims';
            preg_match($regex, $stub, $match);
            var_dump($regex, $match);
            $stub = preg_replace($regex, '\\1\\3\\4', $stub);
            $stub = str_ireplace($keyword, $replace, $stub);
            $results[] = $stub;
        }
    }
    $results = array_unique($results);
    return $results;
}

好的,所以要做的就是返回一个包含$maxStubSize单词的匹配数组(即该数字之前的一半,之后的一半)…

因此,给定一个字符串

<p>a whole 
    <b>bunch of</b> text 
    <a>here for</a> 
    us to foo bar baz replace out from this string
    <b>bar</b>
</p>

调用getKeywordStubs($string, array('bar', 'bunch'))将导致:

array(4) {
  [0]=>
  string(75) "here for us to foo <span class="highlight">bar</span> baz replace out from "
  [3]=>
  string(34) "<span class="highlight">bar</span>"
  [4]=>
  string(62) "a whole <span class="highlight">bunch</span> of text here for "
  [7]=>
  string(39) "<span class="highlight">bunch</span> of"
}

所以,那么您可以通过对列表进行排序strlen,然后选择两个最长的匹配项来构建结果blurb (假设php 5.3+):

usort($results, function($str1, $str2) { 
    return strlen($str2) - strlen($str1);
});
$description = implode('...', array_slice($results, 0, 2));

结果是:

here for us to foo <span class="highlight">bar</span> baz replace out...a whole <span class="highlight">bunch</span> of text here for

我希望有帮助…(我确实觉得这有点......肿…我敢肯定有更好的方法可以做到这一点,但这是一种方法)…



 类似资料:
  • 在功能文档中,据说vespa支持类似关键字高亮的搜索引擎。我找不到任何关于如何实现它的例子。

  • 问题内容: 我正在使用此代码突出显示搜索关键字: 但是,这仅突出显示一个关键字。如果用户输入多个关键字,则会缩小搜索范围,但不会突出显示任何单词。如何突出显示多个单词? 问题答案: 正则表达式是必经之路! 要以不区分大小写的方式进行匹配,请在正则表达式中添加“ i” 注意:对于像“ä”这样的非英语字母,结果可能会因地区而异。

  • 问题内容: 如果包含关键字,该如何编写整个单词的脚本? 示例: 关键字“ fun”,字符串-鸟很有趣,结果-鸟很有趣*。我做以下 但它只是修饰词。我的鸟是 乐趣 纽约 问题答案: 尝试这个: 匹配关键字前面的任何单词字符(至少)和关键字后面的任何单词字符。 并且我建议您使用转义关键字: 为了支持Unicode,请使用 u 标志,而不要使用:

  • 本文向大家介绍HTML 突出显示,包括了HTML 突出显示的使用技巧和注意事项,需要的朋友参考一下 示例 该<mark>元素是HTML5中的新元素,用于“由于其在另一个上下文中的相关性”而标记或突出显示文档中的文本。1 最常见的示例是用户输入搜索查询并显示结果以突出显示所需查询的搜索结果。 输出: 常见的标准格式是黄色背景上的黑色文本,但是可以使用CSS进行更改。

  • 如果所有未分析的字段与搜索查询匹配,我希望突出显示它们。 索引实体如下所示: 假设我有一个,它带有,然后运行一个具有相同值的搜索查询,并使用以下代码突出显示搜索结果: 因此,我得到以下代码片段:. 这似乎是合理的,因为分析器将符号视为停止字,而将视为分隔符,并且不突出显示它们。但是我不知道如何在突出显示这个字段的同时避免使用analyzer。类中有一些方法需要而不是,但我不知道如何使用它们。 我想

  • 问题内容: 我希望突出显示匹配的结果。如果我提到字段名称,它对我有用,它返回突出显示的文本,但是,如果我将字段指定为“ _all”,则它不返回任何值。这对我有用: 这将返回预期值,如下所示:[突出显示] => stdClass对象([my_field] =>数组([0] => stackoverflow 是最适合技术人员的网站)) 但是当我给这个: 我得到空值/无结果。 如何使它在任何字段上都能使