长篇小说关键字瞬间过滤

提到关键字搜索,首先联想到的无非就是使用一些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>
posted @ 2016-03-10 18:25  BigPanda  阅读(642)  评论(0编辑  收藏  举报