突出显示段落中的关键字

2024-02-29

我需要突出显示段落中的关键字,就像谷歌在其搜索结果中所做的那样。假设我有一个包含博客文章的 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 解决方案(例如regex or str_replace)因为突出显示诸如“div”之类的内容有可能完全破坏您的 HTML...这只会“突出显示”正文中的字符串,而永远不会“突出显示”标签内的字符串...


Edit既然你想要 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>

Calling 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然后选择两个最长的匹配...(假设 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 

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

突出显示段落中的关键字 的相关文章

随机推荐

  • 未加权无向图中的最长路径

    以此图作为参考 假设我想要 0 到 5 之间的最长路径 那将是 0 gt 1 gt 3 gt 2 gt 4 gt 6 gt 5 有什么好的算法吗 我已经搜索过 但没有找到任何我能理解的东西 我发现了很多最短路径的算法 0 gt 1 gt 2
  • Python:Struct.pack(format, [...]),虽然格式几乎相同,但打包数据的大小不同

    import struct data struct pack ici 1 chr 1 1 print len data 12 data struct pack iic 1 1 chr 1 print len data 9 两个 data 变
  • 连接 MongoDB Atlas 与 Mongoose 时出现超时错误

    我正在尝试使用 mongoose 连接到 MongoDB Atlas 上的数据库 但每次它都会给我以下错误 node 2327 UnhandledPromiseRejectionWarning Error queryTxt ETIMEOUT
  • 密码和不同类型的加密

    我知道 我知道 类似的问题已经被问过数百万次了 但由于大多数问题都有不同的风格 所以我有自己的风格 目前我正在开发一个网站 该网站打算在全国范围内推出 因此需要对用户系统进行某种保护 我最近读了很多关于密码加密 散列 加盐 凡是你能想到的内
  • ios:使用 GLEssentials 示例代码显示简单的 3D 模型

    我的目标是显示一个简单的 3D 模型并在其上应用纹理 我已经下载了 GLEssentialsios示例项目 http developer apple com library ios samplecode GLEssentials Intro
  • 删除 SimpleForm 生成的选择字段的空白选项

    我有这段代码 f input category as gt select label gt false collection gt Choices Categories Choices Categories 只是 key gt value
  • 使用 TCP 的模拟器连接

    又嗨了 我正在尝试连接在同一台 PC 上作为服务器和客户端运行的两个模拟器 问题是其中一个位于虚拟机内 每个模拟器应该使用什么地址才能在它们之间进行连接 我正在使用基于 TCP 的连接 第一个模拟器在 Windows 7 上运行 Vmwar
  • 适用于高带宽应用的 WebRTC 数据通道

    我想通过 WebRTC 数据通道发送单向流数据 并且正在寻找最佳配置选项 高带宽 低延迟 抖动 以及其他人在此类应用程序中的预期比特率的经验 我的测试程序发送 2k 的块 使用 2k 的 bufferedAmountLowThreshold
  • 找不到 ID 为“xxx”的 UpdatePanel。如果它是动态更新的,那么它必须位于另一个 UpdatePanel 内

    我有一个带有 Ajax 选项卡控件的页面 其中一个选项卡中有一个 Web 控件 它是 Telerik RadGrid 其中编辑表单指向另一个 Web 控件 该编辑表单还包含 Ajax 选项卡 并且在其中一个选项卡上 还有另一个 Web 控件
  • Matlab 中的曲面图

    我正在尝试用对角矩阵绘制曲面 我正在尝试绘制的方程是 f x TDx x 是 2 x 1 向量 D 是 2 x 2 矩阵 这是到目前为止的内容 但我不断收到错误 x linspace 10 10 y linspace 10 10 X Y m
  • 如何将推文居中?

    Twitter 提供了嵌入推文的代码 例如我有 blockquote class twitter tweet p NoSQL space gradually becoming SlowSQL space p mdash Big Data B
  • 为什么我的 TreeSet 不添加第一个元素之外的任何内容?

    我有几个形式的数组 private static String patientNames John Lennon Paul McCartney George Harrison Ringo Starr 然后我制作一个像这样的 TreeSet
  • R knit:可以以编程方式修改块标签吗?

    我正在尝试使用 knit 生成一份报告 该报告对数据集的不同子集执行相同的分析集 该项目包含两个 Rmd 文件 第一个文件是设置工作区和文档的主文档 第二个文件仅包含执行分析并生成相关图形的块 我想做的是编织主文件 然后为每个数据子集调用第
  • Cin 对象返回值 C++ [重复]

    这个问题在这里已经有答案了 我想问一下cin的返回值是多少 我知道它是 ifstream 对象 并且当它在表达式中使用时 如if cin 实际上有一个函数被调用 我想知道它实际上是什么函数 cin fail 或 cin good 或 是if
  • SQL Server 2000 中的交叉表查询

    我希望以前有人尝试过这一点 并且在我进一步之前可以得到一些建议 我希望在 sql server 2000 中生成类似于交叉表查询的内容 我有一个类似于以下的表结构 Item Item Parameter Parameter id item
  • 在我的 iOS 应用程序中实施新的 Google 地图 SDK

    更新 我刚刚收到一封来自 Google 的有关新 Google 地图 iOS SDK 的电子邮件 看来一切都已经解决了 我已成功为我的应用程序创建新的 API 密钥 还没有测试过 但看起来是正确的 他们派我来this https devel
  • 我应该何时以及如何使用 ThreadLocal 变量?

    我什么时候应该使用ThreadLocal https docs oracle com javase 8 docs api java lang ThreadLocal html多变的 它是如何使用的 一种可能 也是常见 的用途是当您有一些非线
  • PHP cURL:获取重定向目标,而不跟随它

    curl getinfo 函数返回大量有关 HTTP 请求结果的元数据 但是 由于某种原因 它不包含我目前想要的信息 如果请求返回 HTTP 重定向代码 则该信息是目标 URL 我没有使用 CURLOPT FOLLOWLOCATION 因为
  • 在 React Native 中使用 mobx 进行状态存储时无法导航到不同的导航菜单

    我对 Mobx 有点陌生 一般来说 我的反应是原生的 我正在尝试使用 mobx 在导航堆栈中实现状态值更改 以便当单击登录按钮时 状态中的值会发生更改 并且导航值参数令牌会更新为 mobx 存储中的最新值 但这不起作用 我收到错误错误任何导
  • 突出显示段落中的关键字

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