长篇小说关键字瞬间过滤
提到关键字搜索,首先联想到的无非就是使用一些indexOf,replace之类的字符函数,最多加上一些正则表达式而已.实现起来虽然很简单,但是这背后的效率问题可曾仔细考虑过?例如论坛中的关键字过滤,一般情况下需过滤的关键字数量及检测的文本长度都不大,所以这一瞬间的过程没有太多值得关注的地方。但若关键字数量不在是屈指可数,而是有成千上万, 并且待检测的文本也是一长篇大论,结果可不再是那么乐观了。大家都知道,每多一个关键字,就要增加一次全文的检索,最终花费的时间将远远超出可接受的范围内。
废话不多说。直接上代码第一种是用正则写的,演示链接:http://zpf92.github.io/build/test.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>关键词过滤</title> </head> <style type="text/css"> *{ padding: 0; margin: 0; } body{ text-align: center; font-size:14px; } textarea,#content{ background: #EEE; border: #999 solid 1px; display: block; margin: 0 auto; width: 95%; } #t1{ height: 100px; } #t2,#content{ height: 400px; text-align: left; } #content{ overflow: auto; font-size:15px; display: none; } #content>span{ color: red; } p{ color: red; font-size: 18px; margin-top: 10px; } #time{ color: lightgreen; } </style> <body> <h2>请输入关键字,中间用;隔开^_^<span>(<i style="color: red;" id="count1">0</i>个)</span></h2> <textarea id="t1"></textarea> <h2>内容<span>(<i style="color: red;" id="count2">0</i>字)</span></h2> <textarea id="t2"></textarea> <div id="content"></div> <input type="button" name="" id="btn" value="过滤"/> <input type="button" id="reset" value="重置"/></br> <p>搜索用时 : <span id="time">0</span> ms</p> <script type="text/javascript"> function $(id){ return document.getElementById(id); } //获取元素 var oBtn = $('btn'), oT1 = $('t1'), oT2 = $('t2'), oC1 = $('count1'), oC2 = $('count2'), oReset = $('reset'), oContent = $('content'), nTime = $('time'), bOk = false, reg; document.addEventListener('click',openTxt,false); function openTxt(){ window.open('http://zpf92.github.io/build/source.txt','blank'); document.removeEventListener('click',openTxt,false); } //去除重复的关键字 function remove(arr){ var arr2 = []; for(var i=0;i<arr.length;i++){ var result=''; if((!findInArr(arr2,arr[i]))&&arr[i]){ for(var j=0;j<arr[i].length;j++){ if(isNaN(arr[i].charAt(j))){ result+='\\'+arr[i].charAt(j); }else{ result+=arr[i].charAt(j); } } arr2.push(result); } } //console.log(arr2); reg=new RegExp(arr2.join('|'),'g'); return arr2.length; } function findInArr(arr,item){ for(var i=0;i<arr.length;i++){ if(arr[i]===item){ return true; } } return false; } //获取关键字总个数 oT1.addEventListener('input',function(){ var value = this.value, n; if(!this.value){ n = 0; }else{ //考虑用户输入了重复的关键字 n = remove(value.split(';')); } oC1.innerHTML = n; //console.log(reg); bOk = true; },false); //获取内容的字数 oT2.addEventListener('input',function(){ oC2.innerHTML = this.value?this.value.length:0; bOk = true; },false); //点击过滤关键字 oBtn.addEventListener('click',function(){ //判断用户是否输入关键字或者内容 if(oT1.value===''&&oT2.value===''){ alert('亲,您两个都没输入,我怎么过滤 ^_^'); return; }else if(oT1.value===''){ alert('亲,您没输入关键字,我怎么过滤 ^_^'); return; }else if(oT2.value===''){ alert('亲,您没输入内容,我怎么过滤 ^_^'); return; } this.disabled = true; oReset.disabled = false; oT1.disabled = true; //var time=new Date().getTime(); var time=performance.now(); oContent.innerHTML = oT2.value.replace(reg,function(str){ return '<span>'+str+'</span>'; }); //nTime.innerHTML=new Date().getTime()-time; nTime.innerHTML=(performance.now()-time).toFixed(3); oContent.style.display = 'block'; oT2.style.display = 'none'; },false); oReset.addEventListener('click',function(){ this.disabled = true; oBtn.disabled = false; oT1.disabled = false; oContent.style.display = 'none'; oT2.style.display = 'block'; },false); </script> </body> </html>
这种是我自己写的,正则每次都是重头开始找而且着了很多次,所以对于一个百万字数的小说关键字过滤耗时太长,下面请大家看下面的代码:
演示链接 http://zpf92.github.io/build/test3.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <style type="text/css"> *{ padding: 0; margin: 0; } body{ text-align: center; font-size:14px; } textarea,#content{ background: #EEE; border: #999 solid 1px; display: block; margin: 0 auto; width: 95%; } #t1{ height: 100px; } #t2,#content{ height: 400px; text-align: left; } #content{ overflow: auto; font-size:15px; display: none; } #content>span{ color: red; } p{ color: red; font-size: 18px; margin-top: 10px; } #time{ color: lightgreen; } </style> <body> <h2>关键字<span>(<i style="color: red;" id="count1">0</i>个)</span></h2> <textarea id="t1"></textarea> <h2>内容<span>(<i style="color: red;" id="count2">0</i>字)</span></h2> <textarea id="t2"></textarea> <div id="content"></div> <input type="button" name="" id="btn" value="过滤"/> <input type="button" id="reset" value="重置"/></br> <p>搜索用时 : <span id="time">0</span> ms</p> <script type="text/javascript"> function $(id){ return document.getElementById(id); } //获取元素 var oBtn = $('btn'), oT1 = $('t1'), oT2 = $('t2'), oC1 = $('count1'), oC2 = $('count2'), oReset = $('reset'), oContent = $('content'), nTime = $('time'), bOk = false; document.addEventListener('click',openTxt,false); function openTxt(){ window.open('http://zpf92.github.io/build/source.txt','blank'); document.removeEventListener('click',openTxt,false); } //去除重复的关键字 function remove(arr){ var arr2 = []; for(var i=0;i<arr.length;i++){ if(!findInArr(arr2,arr[i])){ arr2.push(arr[i]); } } return arr2.length; } function findInArr(arr,item){ for(var i=0;i<arr.length;i++){ if(arr[i]===item){ return true; } } return false; } //获取关键字总个数 oT1.addEventListener('input',function(){ var value = this.value, n; if(!this.value){ n = 0; }else{ //考虑用户输入了重复的关键字 n = remove(value.split(';')); } oC1.innerHTML = n; bOk = true; },false); //获取内容的字数 oT2.addEventListener('input',function(){ oC2.innerHTML = this.value?this.value.length:0; },false); //点击过滤关键字 oBtn.addEventListener('click',function(){ //判断用户是否输入关键字或者内容 if(oT1.value===''&&oT2.value===''){ alert('亲,您两个都没输入,我怎么过滤 ^_^'); return; }else if(oT1.value===''){ alert('亲,您没输入关键字,我怎么过滤 ^_^'); return; }else if(oT2.value===''){ alert('亲,您没输入内容,我怎么过滤 ^_^'); return; } var enterValue = oT2.value; //用于存储输出的内容 var html=[]; //用于标记不是关键字的位置 var index=0; this.disabled = true; oReset.disabled = false; if(bOk){ makeTree(oT1.value); bOk = false; } //开始搜索 var time = performance.now(); var arrMath = search(oT2.value); //显示搜索用时 nTime.innerHTML = (performance.now()-time).toFixed(3); for(var i=0;i<arrMath.length;i+=2){ html.push(enterValue.substring(index,arrMath[i]), '<span>', enterValue.substring(arrMath[i],index=arrMath[i+1]), '</span>' ); } //防止尾部漏掉 html.push(enterValue.substring(index)); oContent.innerHTML = html.join(''); oContent.style.display = 'block'; oT2.style.display = 'none'; },false); //重新设置 oReset.addEventListener('click',function(){ this.disabled = true; oBtn.disabled = false; oT1.disabled = false; oContent.style.display = 'none'; oT2.style.display = 'block'; },false); var root; //将关键字生成一棵树 function makeTree(sValue){ var arr = sValue.split(''); var cur = root = {}; for(var i=0;i<arr.length;i++){ var key = arr[i]; if(key===';'){ cur.end = true; cur = root; continue; } if(key in cur){ cur = cur[key]; }else{ cur = cur[key] = {}; } } cur.end=true; } function search(sValue){ var n=sValue.length; var cur; var arrMath=[]; var i=0,p,v; while(i<n){ cur = root; p = i; v = 0; for(;;){ if(!(cur=cur[sValue.charAt(p++)])){ i++; break; } if(cur.end){ v = p; } } if(v){ arrMath.push(i-1,v); i = v; } } return arrMath; } </script> </body> </html>
若需转载,请注明出处,谢谢合作!