利用原生JavaScript实现匹配搜索结果的网页内容高亮

news2024/11/15 22:52:36

昨天在用Anki的时候,复习笔记时想在笔记的解析里快速查找内容,于是探索了一下将匹配的搜索结果高亮。开始想不用第三方库直接实现,结果匹配的文本被HTML标签隔断时不能成功匹配,后来用到了jquery的mark.js库才简单实现。事后我想看看人工智能能不能解决不借助已有的库实现那个功能,结果人工智能给我一个页面代码,我用来一试,完全是被忽悠。不过人工智能的代码给了我一个提示——可以将搜索文本分成一个个字符,然后在两个字符中间插入匹配HTML标签的正则表达式,设定正则表达式可以出现非负整数次,就能够成功消除HTML标签的影响了。

于是进行了一番编码和调试,基本功能是实现了,潜在bug则没有测试,代码如下:

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Search Highlighter</title>
    <style>
        .highlight {
            background-color: yellow;
        }
    </style>
</head>
<body>
    <input type="text" id="searchInput" value="is">
    <button onclick="search()">Search</button>
    <div id="textContainer">
        This is some sample text to search through. You can replace this with your own content.
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed et quam eget ipsum ullamcorper hendrerit.
        Donec vitae quam eget quam aliquam tincidunt. Nullam pharetra quam ac quam tincidunt, at semper ipsum
        varius. Donec nec enim at libero ullamcorper hendrerit. Sed ac quam eget quam aliquam tincidunt.
        Nullam pharetra quam ac quam tincidunt, at semper ipsum varius.
        我i<b>s们This is. some bold text.</b>
        <i>This is some italic text.</i>
        <a href="#">This is a link.</a>
    </div>
    <script>
        function search() {
            const searchTerm = document.getElementById('searchInput').value.toLowerCase();
            const textContainer = document.getElementById('textContainer');
            //清除已有的高亮,其实就是删除成对的高亮格式span标签
            textContainer.innerHTML = textContainer.innerHTML.replaceAll(/<span class="highlight">(.+?)<\/span>/gi,'$1');
            const text = textContainer.innerHTML;
            const eleTag = '(<[^>]+>){0,}';
            let sReg = '';
            let highlightedHTML = '';
            //将查找字符串拆成单个字符,中间插入eleTag,于是可以匹配相连的两个字符中间有0个或多个html标签
            searchTerm.split('').forEach(char=>{
                //这里应该将JavaScript正则表达式用到的转义字符都转换一遍,这里只处理了两个,肯定存在bug
                if(char === ' ') char = '\\s';
                else if(char === '.') char = '\\.';
                sReg = `${sReg}${char}${eleTag}`;
            });

            const regex = new RegExp(sReg, 'ig');
            let matches;
            let pos = 0;//用于记录一次成功匹配后到达的位置
            while((matches = regex.exec(text)) !== null){//匹配成功
                let tmp = matches[0];
                //截取上次匹配处理后至本次匹配之间的HTML片段,准备添加高亮标签
                let ret = text.substring(pos, regex.lastIndex);
                pos = regex.lastIndex;
                /*
                 * 如果匹配成功的内容里有HTML标签,我们需要在标签前面插入一个span结束标签,
                 * 标签后面插入一个开始标签,这样才不会破坏原有的HTML文档结构。
                 */
                const regTag = new RegExp('(<[^>]+>)', 'ig');
                tmp = tmp.replaceAll(regTag,'</span>$1<span class="highlight">');
                //再在匹配成功的内容最前面加上高亮开始标签,末尾加上高亮结束标签,闭合
                tmp = `<span class="highlight">${tmp}</span>`;
                //将匹配内容替换为添加了高亮标签的html片段
                ret = ret.replace(matches[0],tmp);
                //拼接到最终HTML字符串中
                highlightedHTML = `${highlightedHTML}${ret}`;
            }
            //替换原有HTML片段,实现高亮
            textContainer.innerHTML = `${highlightedHTML}${text.substring(pos)}`;
        }

    </script>
</body>
</html>

为什么那上面有那么多英文?因为人工智能给我的就是英文,HTML内容我只插入了两个汉字,然后在原有的<b>标签前后分别插入了一个i和s。运行截图如下:

再搜索一次:

进行一次没有匹配内容的搜索:

反正就是玩玩,就这样吧。人工智能给的原始文件附上:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Search Highlighter</title>
    <style>
        .highlight {
            background-color: yellow;
        }
    </style>
</head>
<body>
    <input type="text" id="searchInput" placeholder="Enter search term">
    <button onclick="search()">Search</button>
    <div id="textContainer">
        This is some sample text to search through. You can replace this with your own content.
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed et quam eget ipsum ullamcorper hendrerit.
        Donec vitae quam eget quam aliquam tincidunt. Nullam pharetra quam ac quam tincidunt, at semper ipsum
        varius. Donec nec enim at libero ullamcorper hendrerit. Sed ac quam eget quam aliquam tincidunt.
        Nullam pharetra quam ac quam tincidunt, at semper ipsum varius.
        <b>This is some bold text.</b>
        <i>This is some italic text.</i>
        <a href="#">This is a link.</a>
    </div>
    <script>
        function search() {
            const searchTerm = document.getElementById('searchInput').value.toLowerCase();
            const textContainer = document.getElementById('textContainer');
            const text = textContainer.textContent.toLowerCase();

            const regex = new RegExp(`(<[^>]+>|\&nbsp;)|(${searchTerm})`, 'ig');

            let highlightedHTML = '';
            const textParts = text.replace(regex, function(match, htmlTag, searchTerm) {
                if (htmlTag) {
                    return htmlTag;
                } else {
                    return `<span class="highlight">${searchTerm}</span>`;
                }
            }).split(/<\/?span>/);

            for (const part of textParts) {
                if (part.startsWith('<span')) {
                    highlightedHTML += `<span class="highlight">${part.slice(6)}</span>`;
                } else {
                    highlightedHTML += part;
                }
            }

            textContainer.innerHTML = highlightedHTML;
        }
    </script>
</body>
</html>

它根本就不能工作。不过,里面的正则表达式“<[^>]+>”和变量名“textParts”是我最终代码思路的源泉。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1915087.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue中v-if与v-show的区别

在 Vue.js 中&#xff0c;v-if 和 v-show 都是用来控制元素显示与隐藏的指令&#xff0c;但它们之间有几个关键的区别&#xff1a; 直接上图 一. 条件渲染方式不同 v-if&#xff1a; 真正的条件渲染&#xff1a;v-if 指令会根据表达式的真假来销毁或重新创建 DOM 元素及其…

拟合衰减振动模型,估算阻尼比和阻尼系数

拟合衰减振动模型&#xff0c;估算阻尼比和阻尼系数 flyfish 衰减振动模型 在自由振动系统中&#xff0c;阻尼振动可以用以下公式描述&#xff1a; x ( t ) x 0 e − ζ ω n t cos ⁡ ( ω d t ϕ ) x(t) x_0 e^{-\zeta \omega_n t} \cos(\omega_d t \phi) x(t)x0​e−…

数据结构与算法-动态规划-三角形最小路径和

三角形最小路径和 给定一个三角形 triangle &#xff0c;找出自顶向下的最小路径和。 每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 1 的两个结点。也就是说&#xff0c;如果正位于当前行的下标 i &…

JUC并发编程-05:线程高级部分-源码解读

线程高级部分-源码解读 多线程高并发底层锁机制与优化最佳实践深入JDK源码理解LongAdder的分段CAS优化机制 公平锁和非公平锁原理解析 多线程高并发底层锁机制与优化最佳实践 深入JDK源码理解LongAdder的分段CAS优化机制 多个线程进入&#xff0c;为了防止空转&#xff0c;所…

Android11 窗口动画

窗口进入动画 应用端窗口绘制完成之后&#xff0c;调用finshDraw告知WMS&#xff0c;WMS这边最后就会调用WindowSurfacePlacer的performSurfacePlacement方法&#xff0c;最终调用到 WindowStateAnimator的commitFinishDrawingLocked方法 //frameworks/base/services/core/jav…

基于Transformer的端到端的目标检测 | 读论文

本文正在参加 人工智能创作者扶持计划 提及到计算机视觉的目标检测&#xff0c;我们一般会最先想到卷积神经网络&#xff08;CNN&#xff09;&#xff0c;因为这算是目标检测领域的开山之作了&#xff0c;在很长的一段时间里人们都折服于卷积神经网络在图像处理领域的优势&…

Redis 主从复制,集群与高可用

虽然Redis可以实现单机的数据持久化&#xff0c;但无论是RDB也好或者AOF也好&#xff0c;都解决不了单点宕机问题&#xff0c;即一旦单台 redis服务器本身出现系统故障、硬件故障等问题后&#xff0c;就会直接造成数据的丢失 此外,单机的性能也是有极限的,因此需要使用另外的技…

数字安全护航技术能力全景图 | 亚信安全实力占据75领域

近日&#xff0c;2024全球数字经济大会——数字安全生态建设专题论坛在北京成功举办。会上&#xff0c;中国信息通信研究院&#xff08;简称“中国信通院”&#xff09;正式发布了《数字安全护航技术能力全景图》&#xff0c;亚信安全凭借全面的产品技术能力&#xff0c;成功入…

蓝卓创始人褚健:工业软件是数字化转型的灵魂和核心驱动力

如果把“工业3.0”简单理解为就是“自动化”&#xff0c;“工业4.0”理解为是“智能化”&#xff0c;那么“智能化”的实现一定要有软件。如同今天的移动互联网&#xff0c;是因为有大量的APP&#xff0c;所以让人们进入了智能时代。映射到工业、制造业领域&#xff0c;就是要依…

[GICv3] 4. 中断分发和路由(Distribution and Routing)

&#x1f4a1;介绍如何将中断分发和路由到目标PE&#xff0c;以及中断号的分配。 分发和重分发&#xff08;The disributor an Redistributors&#xff09; 分配器为SPI提供路由配置&#xff0c;并持有所有相关的路由和优先级信息。重新分配器提供PPI和SGI的配置设置。 重新分…

京东速运|通过python查询快递单号API

本次讲解如何使用快递聚合供应商来实现查询京东速运快递物流轨迹&#xff0c;首先&#xff0c;我们需要准备的资源。 平台的密钥key&#xff1a;登录后在个人中心查看 测试接口的链接&#xff1a;在下方文档处查看 其中&#xff0c;KEY为用户后台我的api页面展示的API密钥, 代…

《米小圈漫画历史》:历史启蒙,看漫画书就可以啦!

在当今信息爆炸的时代&#xff0c;如何让孩子在娱乐中学习&#xff0c;一直是许多家长关心的问题。《米小圈漫画历史》系列作为一部集合了趣味性和教育性的漫画书&#xff0c;以其独特的视角和精彩的故事情节&#xff0c;成为了许多家庭历史启蒙的首选。本文将通过探索漫画书的…

MT3046 愤怒的象棚

思路&#xff1a; a[]存愤怒值&#xff1b;b[i]存以i结尾的&#xff0c;窗口里的最大值&#xff1b;c[i]存以i结尾的&#xff0c;窗口里面包含✳的最大值。 &#xff08;✳为新大象的位置&#xff09; 例&#xff1a;1 2 3 4 ✳ 5 6 7 8 9 则ans的计算公式b3b4c4c5c6b7b8b9…

探索AI大模型(LLM)减少幻觉的三种策略

大型语言模型&#xff08;LLM&#xff09;在生成文本方面具有令人瞩目的能力&#xff0c;但在面对陌生概念和查询时&#xff0c;它们有时会输出看似合理却实际错误的信息&#xff0c;这种现象被称为“幻觉”。近期的研究发现&#xff0c;通过策略性微调和情境学习、检索增强等方…

Linux基础指令解析+项目部署环境

文章目录 前言基础指令部署项目环境总结 前言 Linux的魅力在于其强大的可定制性和灵活性&#xff0c;这使得它成为了众多开发者和运维人员的首选工具。然而&#xff0c;Linux的指令系统庞大而复杂&#xff0c;初学者往往容易迷失其中。因此&#xff0c;本文将带领大家走进Linu…

一键换衣,这个AI可以让你实现穿衣自由

基于图像的虚拟穿衣是一种流行且前景广阔的图像合成技术&#xff0c;能够显著改善消费者的购物体验&#xff0c;并降低服装商家的广告成本。顾名思义&#xff0c;虚拟穿衣任务旨在生成目标人穿着给定服装的图像。 OOTDiffusion简述 图1 虚拟换衣 基于图像的虚拟穿衣目前面临两…

解决linux服务器下微信公众号授权和业务接口授权失败的问题

我们的公众号web站点代码在Windows服务器IIS下运行没有问题&#xff0c;迁移到linux 服务器的nginx下之后&#xff0c;出现了微信授权和接口授权无法通过引起的问题。如下图所示&#xff1a; 经过排查&#xff0c;发现是因为nginx配置默认对 http 配置节下的 underscores_in_he…

MySQL黑马教学对应视屏笔记分享之聚合函数,以及排序语句的讲解笔记

聚合函数 注意&#xff1a;null值不参与聚合函数的计算。 分组查询 2.where与having的区别 执行时机不同&#xff1a;where是在分组之前进行过滤&#xff0c;不满足where条件&#xff0c;不参与分组&#xff1b;而having是分组之后对结果进行过滤。判断条件不同&#xff1a;w…

3,区块链加密(react+区块链实战)

3&#xff0c;区块链加密&#xff08;react区块链实战&#xff09; 3.1 哈希3.2 pow-pos-dpos3.3非对称加密&#xff08;1&#xff09;对称加密AES&#xff08;2&#xff09;非对称加密RSA 3.4 拜占庭将军3.5 P2P网络3.6 区块链 3.1 哈希 密码学&#xff0c;区块链的技术名词 …

【SQL】MySQL中的字符串处理函数:concat 函数拼接字符串,COALESCE函数处理NULL字符串

MySQL中的字符串处理函数&#xff1a;concat 函数 一、concat &#xff08;&#xff09;函数1.1、基本语法1.2、示例1.3、特殊用途 二、COALESCE&#xff08;&#xff09;函数2.1、基本语法2.2、示例2.3、用途 三、进阶练习3.1 条件和 SQL 语句3.2、解释 一、concat &#xff0…