使用jquery对html内容进行跨标签的关键词检索

本人后端狗,接触过一些html、javascript,这个问题是组内前端小伙伴遇到的,帮他解决了这个问题

问题描述:将word文件转为html后在页面显示,需要对这部分html内容进行关键词搜索高亮,但转换后的文字被拆分,被包含在各种标签里,很多内容检索不到。
解决过程如下:

  1. 直接对html片段使用模糊匹配
    *关键词在同一个标签内有效
    -关键词被拆分到不同标签里,页面上可以看到这个关键词,但是搜索不到
    -误匹配到html标签,造成页面显示异常
  2. 使用jquery插件(jquery.textSearch-1.0.js插件原文链接
    *关键词在同一个标签内有效
    *解决误匹配html标签的问题
    -关键词被拆分到不同标签里,页面上可以看到这个关键词,但是搜索不到
  3. 对jquery.textSearch插件进行改造
    阅读了插件的源码,发现他是用正则将HTML代码支离为HTML片段和文字片段,其中文字片段用于正则替换处理,而HTML片段置之不理,处理好后再合并这些片段
    拆分html的思路很棒,但是他只对单个文字片段进行替换,如果关键词包括了前后几个文字片段方法就失效了
    于是我他的基础上补充了一部分代码,判断文字片段包含的关键词的开头部分,并且关键词包含了后面的连续文字片段,最后一个文字片段又包含关键词结尾部分,就可以匹配上跨标签的文字。
    *关键词在同一个标签内有效
    *解决误匹配html标签的问题
    *关键词被拆分到不同标签里同样有效
  4. 实际使用中可以根据需要进行改造,比如使用正则表达式拆分出空格,这样即使原文片段里含有空格也不影响检索。
    也可以将该jquery插件用vue等方式重写,欢迎分享

附上修改后的代码,有点长


// update by vinci

(function($){
    $.fn.textSearch = function(str,options){
        var defaults = {
            divFlag: true,
            divStr: " ",
            markClass: "mark",
            markColor: "",
            cardColor: "",
            markType: "font",
            markBackground: "",
            nullReport: true,
            callback: function(){
                return false;   
            }
        };
        var sets = $.extend({}, defaults, options || {}), clStr;
        if(sets.markClass){
            clStr = "class='"+sets.markClass+"'";   
        }
        if(sets.cardColor){
            clStr += " style='color:"+sets.cardColor+"; cursor: pointer;text-decoration:underline;'";
        }
        if(sets.markColor){
            clStr += " style='color:"+sets.markColor+";'";
        }
        if(sets.markBackground){
            clStr += " style='background:"+sets.markBackground+";'";
        }
        
        
        
        //对前一次高亮处理的文字还原     
        // $("."+sets.markClass).each(function() {
        //  var text = document.createTextNode($(this).text()); 
        //  $(this).replaceWith($(text));
        // });
        
        
        //字符串正则表达式关键字转化
        $.regTrim = function(s){
            var imp = /[\^\.\\\|\(\)\*\+\-\$\[\]\?]/g;
            var imp_c = {};
            imp_c["^"] = "\\^";
            imp_c["."] = "\\.";
            imp_c["\\"] = "\\\\";
            imp_c["|"] = "\\|";
            imp_c["("] = "\\(";
            imp_c[")"] = "\\)";
            imp_c["*"] = "\\*";
            imp_c["+"] = "\\+";
            imp_c["-"] = "\\-";
            imp_c["$"] = "\$";
            imp_c["["] = "\\[";
            imp_c["]"] = "\\]";
            imp_c["?"] = "\\?";
            s = s.replace(imp,function(o){
                return imp_c[o];                       
            }); 
            return s;
        };
        $(this).each(function(){
            var t = $(this);
            str = $.trim(str);
            if(str === ""){
                alert("关键字为空"); 
                return false;
            }else{
                //将关键字push到数组之中
                var arr = [];
                if(sets.divFlag){
                    arr = str.split(sets.divStr);   
                }else{
                    arr.push(str);  
                }
            }
            var v_html = t.html();
            //删除注释
            v_html = v_html.replace(/<!--(?:.*)\-->/g,"");
            
            //将HTML代码支离为HTML片段和文字片段,其中文字片段用于正则替换处理,而HTML片段置之不理
            //var tags = /[^<>]+|<(\/?)([A-Za-z]+)([^<>]*)>/g;
            //处理空格问题
            var tags = /[^<>\s]+|[\s]+|[]+|<(\/?)([A-Za-z]+)([^<>]*)>/g;

            var a = v_html.match(tags), test = 0;
            $.each(a, function(i, c){
                if(!/<(?:.|\s)*?>/.test(c)){//非标签
                    //开始执行替换
                    $.each(arr,function(index, con){
                        if(con === ""){return;}
                        var reg = new RegExp($.regTrim(con), "g");
                        if(reg.test(c)){
                            //正则替换
                            c = c.replace(reg,"♂"+con+"♀");
                            c = c.replace(/♂/g,"<"+sets.markType+" "+clStr+">").replace(/♀/g,"</"+sets.markType+">");
                            a[i] = c;
                            test = 1;
                        }else if(containStart(c, con)){
                            var testA = [];
                            var testI = [];
                            testA.push(c);
                            testI.push(i);
                            for(var j=i+1;j<a.length;j++){
                                var aj = a[j]
                                if(!/<(?:.|\s)*?>/.test(aj)){
                                    if(containEnd(aj,con)){
                                        testA.push(aj);
                                        testI.push(j);
                                        if(testA.join("").length >= con.length){
                                            break;
                                        }
                                    }else if(con.indexOf(aj)!=-1){
                                        testA.push(aj);
                                        testI.push(j);
                                    }else if(con.indexOf(aj)==-1){
                                        break;
                                    }
                                }
                            }
                            if(testA.join("").indexOf(con)!=-1){
                                for(var p=0;p<testI.length;p++){
                                    var ind = testI[p];
                                    var ti = testA[p];
                                    var c1;
                                    if(p==0){
                                        var start = getContainStart(ti, con)
                                        c1 = ti.replace(start,"♂"+start+"♀");
                                    }else if(p==testI.length-1){
                                        var end = getContainEnd(ti, con)
                                        c1 = ti.replace(end,"♂"+end+"♀");
                                    }else{
                                        c1 = ti.replace(ti,"♂"+ti+"♀");
                                    }
                                    c1 = c1.replace(/♂/g,"<"+sets.markType+" "+clStr+">").replace(/♀/g,"</"+sets.markType+">");
                                    a[ind] = c1;
                                }
                                test = 1;
                            }
                        }
                    });
                    
                }
            });
            //将支离数组重新组成字符串
            var new_html = a.join("");
            $(this).html(new_html);
            if(test === 0 && sets.nullReport){
                return false;
            }
            
            //执行回调函数
            sets.callback();
        });
    };
})(jQuery);

function confirmEnding(str, target) {
 let strLen = str.length;
 let targetLen = target.length;
 if(str.substring(strLen-targetLen) == target){
   return true;
 }
 return false;
}


function containStart(str, target) {
 var tarL = target.length;
 var strL = str.length;
 for(var i=strL;i>0;i--){
     var tarS = target.substring(0,i);
     if(confirmEnding(str,tarS)){
         return true;
     }
 }
 return false;
}


function getContainStart(str, target) {
 var tarL = target.length;
 var strL = str.length;
 for(var i=strL;i>0;i--){
     var tarS = target.substring(0,i);
     if(confirmEnding(str,tarS)){
         return tarS;
     }
 }
 return "";
}




function containEnd(str, target) {
 var tarL = target.length;
 var strL = str.length;
 for(var i=tarL-strL;i<tarL;i++){
     var tarS = target.substring(i,tarL);
     if(str.indexOf(tarS)==0){
         return true;
     }
 }
 return false;
}

function getContainEnd(str, target) {
 var tarL = target.length;
 var strL = str.length;
 for(var i=tarL-strL;i<tarL;i++){
     var tarS = target.substring(i,tarL);
     if(str.indexOf(tarS)==0){
         return tarS;
     }
 }
 return "";
}

一句小心得:编程语言虽然有很多,但数据结构和算法是相通的

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343