如何在100万文字的文章中 200ms内 快速提取 替换 上万个关键字

关键点:

  关键字 组合 成一棵 hash 树  ( 有属性就直接移动指针到下一个字对象, 没有属性就创建子对象, 再移动指针;  第二次循环在子对象看有没这个属性 )

  探测针       标记结束         跳跃      回溯

var treeSearch = {
        makeTree: function(strKeys) {
            "use strict";

            var tblCur = {},
                tblRoot,
                key,
                str_key,
                Length,
                j,
                i
                ;
            tblRoot = tblCur;

            /*一次性 把所以的关键字 都放在 hash tree中
            abc, abd => {     a:{ b: {c: {end:true}, d: {end: true } } }       }
            
            abcd, bc => { a:{b:{c:{d:{end:true}}}},  b:{c:{end:true}}  }

            */
            for ( j = strKeys.length - 1; j >= 0; j -= 1) {

                str_key = strKeys[j];
                Length = str_key.length;

                for ( i = 0; i < Length; i += 1) {

                    key = str_key.charAt(i);

                    if (tblCur.hasOwnProperty(key)) { //生成子节点
                        tblCur = tblCur[key];
                        
                    } else {
                        //在当前的对象 创建一个子对象

                        // 注意 tblRoot 和 tblCur是指向同一个对象 ori, 虽然tblCur移动了
                        // 但还是指向了对象 ori, 所以利用这个tblCur创建的子对象, 仍然是创建在ori上
                        //  而 tblRoot 也指向了 ori, 所以每次tblRoot
                        tblCur[key] = {}

                        //移动当前指针到 这个新的子对象
                        tblCur = tblCur[key];

                    }
                }

                tblCur.end = true; //最后一个关键字没有分割符

                // 回溯, tblCur 指针从新指向根节点, 变成了整个对象
                tblCur = tblRoot;
            }

            return tblRoot;
        },

        search: function(content, tblRoot) {
            "use strict";
            var tblCur,
                p_safe = 0,
                n = content.length,
                p_tick,
                match,  //是否找到匹配
                match_key,
                match_str,
                arrMatch = [],  //存储结果
                arrLength = 0   //arrMatch的长度索引
                ;
     
            while (p_safe < n) {
                /*
                    tblRoot { a:{ b: {c: {end:true}, d: {end: true }  } },  { }   }

                    n : 10000 
                */
                tblCur = tblRoot; //回溯整个对象, 从整个tree从新匹配  
                p_tick = p_safe;
                match_str = "";
                match = false;

                do {
                    
                    /* UCOKsfKBdaqRYQqSYUYjdvDR 
                        match_key :  U
                    */

                    //这个是字符串 别人的东西
                    match_key = content.charAt(p_tick);  


                    // (向前移动) tblCur指针, 指向下一个 深层子对象
                    /**
                        1.  tblCur:  {a: {b:{}, d:{}} }
                        2.  tblCur:  {b:{}, d{} }
                    */

                    // tblCur 是关键字自己的 tree, 匹配到别人的一个字, 就继续前移匹配另一个
                    tblCur = tblCur[match_key]

                    if (!tblCur) { 
                        
                        //至少说明 以(a) 开头的字母的词组, 从当前位置 往下连续,  是不可能匹配到了   
                        p_safe += 1;   

                        // 确认安全后, 小不点 p_safe 移动一个位置

                        break;    //直接进入到下一次循环  ---->  out
                    } 



                    match_str += match_key;  //保存  [match]

                    p_tick += 1;              // p_safe 小不点,  p_tick 小不点的探测器 (向前移动)

                    if (tblCur.end === true) { //
                        match = true;          //说明这几个木板下有坑
                    }

                } while (true);





     
                if (match === true) { //最大匹配
                    

                    /**
                      把找到的 标记起来
                    **/
                    arrMatch[arrLength] = { //增强可读性
                        key: match_str,
                        begin: p_safe - 1,
                        end: p_tick
                    };
                    arrLength += 1;

                    


                    p_safe = p_tick;   // 小不点直接跳过坑
                }


            }
            return arrMatch;
        }
    }

    function test(strContent, strKeys) {

        var s1 = new Date();

        var arrMatch, item,
            tblRoot = treeSearch.makeTree(strKeys),
            t = new Date();
        
        console.log( t  -  s1)

        for (var i = 0; i < strContent.length; i++) {
              item = strContent[i];

              arrMatch = treeSearch.search(item, tblRoot);

        }
       
         
      
        console.log("time is: " + (new Date() - t) + "ms");
     
        
     
        console.dir(arrMatch);
    }

    var s = (function() {
        var Things = ['汉', '
', '小', '大', '海', '能'];
        var s = "";
        var arr = []
       
        for (var i = 1000000; i >= 0; i--) {

             s += Things[parseInt(Math.random() * Things.length) % Things.length]

            if( i % 50 == 0 ){
                arr.push(s);
                s = '';
            }
           
        };

        return arr;

    })()

    test(s, ["汉能",  "abcd", "bc", 'lala']);
View Code
 var treeSearch = {
        makeTree: function(strKeys) {
            "use strict";

            var tblCur = {},
                tblRoot,
                key,
                str_key,
                Length,
                j,
                i
                ;
            tblRoot = tblCur;

            /*一次性 把所以的关键字 都放在 hash tree中
            abc, abd => {     a:{ b: {c: {end:true}, d: {end: true } } }       }
            
            abcd, bc => { a:{b:{c:{d:{end:true}}}},  b:{c:{end:true}}  }

            */
            for ( j = strKeys.length - 1; j >= 0; j -= 1) {

                str_key = strKeys[j];
                Length = str_key.length;

                for ( i = 0; i < Length; i += 1) {

                    key = str_key.charAt(i);

                    if (tblCur.hasOwnProperty(key)) { //生成子节点
                        tblCur = tblCur[key];
                    } else {
                        //在当前的对象 创建一个子对象

                        // 注意 tblRoot 和 tblCur是指向同一个对象 ori, 虽然tblCur移动了
                        // 但还是指向了对象 ori, 所以利用这个tblCur创建的子对象, 仍然是创建在ori上
                        //  而 tblRoot 也指向了 ori, 所以每次tblRoot
                        tblCur[key] = {}

                        //移动当前指针到 这个新的子对象
                        tblCur = tblCur[key];

                    }
                }

                tblCur.end = true; //最后一个关键字没有分割符

                // 回溯, tblCur 指针从新指向根节点, 变成了整个对象
                tblCur = tblRoot;
            }

            return tblRoot;
        },

        search: function(content, tblRoot) {
            "use strict";
            var tblCur,
                p_star = 0,
                n = content.length,
                p_end,
                match,  //是否找到匹配
                match_key,
                match_str,
                arrMatch = [],  //存储结果
                arrLength = 0   //arrMatch的长度索引
                ;
     
            while (p_star < n) {
                /*
                    tblRoot { a:{ b: {c: {end:true}, d: {end: true }  } },  { }   }

                    n : 10000 
                */
                tblCur = tblRoot; //回溯至根部  
                p_end = p_star;
                match_str = "";
                match = false;

                do {
                    
                    /* UCOKsfKBdaqRYQqSYUYjdvDR 
                        match_key :  U
                    */
                    match_key = content.charAt(p_end);  


                    // (向前移动) tblCur指针, 指向下一个 深层子对象
                    tblCur = tblCur[match_key]

                    if (!tblCur) { 
                        
                        //至少说明 以(a) 开头的字母的词组, 在当前位置是不可能匹配到了   
                        p_star += 1;   
                        // 确认安全后, 小不点 p_start 移动一个位置

                        break;    //直接进入到下一次循环  ---->  out
                    } 

                    match_str += match_key;  //保存  [match]

                    p_end += 1;              // p_star 小不点,  p_end 小不点的探测器 (向前移动)

                    if (tblCur.end === true) { //
                        match = true;          //说明这几个木板下有坑
                    }

                } while (true);
     
                if (match === true) { //最大匹配
                    

                    /**
                      把找到的 标记起来
                    **/
                    arrMatch[arrLength] = { //增强可读性
                        key: match_str,
                        begin: p_star - 1,
                        end: p_end
                    };
                    arrLength += 1;

                    


                    p_star = p_end;   // 小不点直接跳过坑
                }


            }
            return arrMatch;
        }
    }

    function test(strContent, strKeys) {

        var s1 = new Date();

        var arrMatch, item,
            tblRoot = treeSearch.makeTree(strKeys),
            t = new Date();
        
        console.log( t  -  s1)

        for (var i = 0; i < strContent.length; i++) {
              item = strContent[i];

              arrMatch = treeSearch.search(item, tblRoot);

        }
       
         
      
        console.log("time is: " + (new Date() - t) + "ms");
     
        
     
        console.dir(arrMatch);
    }

    var s = (function() {
        var Things = ['汉', '
', '小', '大', '海', '能'];
        var s = "";
        var arr = []
       
        for (var i = 1000000; i >= 0; i--) {

             s += Things[parseInt(Math.random() * Things.length) % Things.length]

            if( i % 50 == 0 ){
                arr.push(s);
                s = '';
            }
           
        };

        return arr;

    })()

    test(s, ["汉能",  "abcd", "bc", 'lala']);
View Code

链接  需要使用树算法, 

var treeSearch = {
    makeTree: function(strKeys) {
        "use strict";
        var tblCur = {},
            tblRoot,
            key,
            str_key,
            Length,
            j,
            i
            ;
        tblRoot = tblCur;
        for ( j = strKeys.length - 1; j >= 0; j -= 1) {
            str_key = strKeys[j];
            Length = str_key.length;
            for ( i = 0; i < Length; i += 1) {
                key = str_key.charAt(i);
                if (tblCur.hasOwnProperty(key)) { //生成子节点
                    tblCur = tblCur[key];
                } else {
                    tblCur = tblCur[key] = {};
                }
            }
            tblCur.end = true; //最后一个关键字没有分割符
            tblCur = tblRoot;
        }
        return tblRoot;
    },
    search: function(content, tblRoot) {
        "use strict";
        var tblCur,
            p_star = 0,
            n = content.length,
            p_end,
            match,  //是否找到匹配
            match_key,
            match_str,
            arrMatch = [],  //存储结果
            arrLength = 0   //arrMatch的长度索引
            ;
 
        while (p_star < n) {
            tblCur = tblRoot; //回溯至根部
            p_end = p_star;
            match_str = "";
            match = false;
            do {
                match_key = content.charAt(p_end);
                if (!(tblCur = tblCur[match_key])) { //本次匹配结束
                    p_star += 1;
                    break;
                }else{
                    match_str += match_key;
                }
                p_end += 1;
                if (tblCur.end === true) //是否匹配到尾部  //找到匹配关键字
                {
                    match = true;
                }
            } while (true);
 
            if (match === true) { //最大匹配
                arrMatch[arrLength] = { //增强可读性
                    key: match_str,
                    begin: p_star - 1,
                    end: p_end
                };
                arrLength += 1;
                p_star = p_end;
            }
        }
        return arrMatch;
    }
};
View Code
function test(strContent, strKeys) {
    var arrMatch,
        tblRoot = treeSearch.makeTree(strKeys),
        t = new Date();
 
 
    arrMatch = treeSearch.search(strContent, tblRoot);
 
    console.log("time is: " + (new Date() - t) + "mm");
 
    console.log(arrMatch);
}
var s = (function() {
    var Things = [' ', '
', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
    var s = "";
    for (var i = 1000000; i >= 0; i--) {
        s += Things[parseInt(Math.random() * Things.length) % Things.length]
    };
    return s;
})()
test(s, ["abc", "efge", "fun", "tree"]);
View Code
 var treeSearch = {
        makeTree: function(strKeys) {
            "use strict";

            var tblCur = {},
                tblRoot,
                key,
                str_key,
                Length,
                j,
                i
                ;
            tblRoot = tblCur;

            for ( j = strKeys.length - 1; j >= 0; j -= 1) {

                str_key = strKeys[j];
                Length = str_key.length;

                for ( i = 0; i < Length; i += 1) {

                    key = str_key.charAt(i);
                    if (tblCur.hasOwnProperty(key)) { //生成子节点
                        tblCur = tblCur[key];
                    } else {
                        //在当前的对象 创建一个子对象
                        tblCur[key] = {}

                        //移动当前指针到 这个新的子对象
                        tblCur = tblCur[key];

                    }
                }

                tblCur.end = true; //最后一个关键字没有分割符

                tblCur = tblRoot;
            }

            return tblRoot;
        },

        search: function(content, tblRoot) {
            "use strict";
            var tblCur,
                p_star = 0,
                n = content.length,
                p_end,
                match,  //是否找到匹配
                match_key,
                match_str,
                arrMatch = [],  //存储结果
                arrLength = 0   //arrMatch的长度索引
                ;
     
            while (p_star < n) {
                /*
                    tblRoot { a:{ b: {c: {end:true}, d: {end: true }  } },  { }   }

                    n : 10000 
                */
                tblCur = tblRoot; //回溯至根部  
                p_end = p_star;
                match_str = "";
                match = false;

                do {
                    
                    /* UCOKsfKBdaqRYQqSYUYjdvDR 
                        match_key :  U
                    */
                    match_key = content.charAt(p_end);  

                    if (!(tblCur = tblCur[match_key])) { // (向前移动) tblCur指针, 指向下一个 深层子对象
                       
                        p_star += 1;   // 确认安全后, 小不点 p_start 移动一个位置

                        break;    //直接进入到下一次循环  ---->  out
                    } 

                    match_str += match_key;  //保存  [match]

                    p_end += 1;              // p_star 小不点,  p_end 小不点的探测器 (向前移动)

                    if (tblCur.end === true) { //
                        match = true;          //说明这几个木板下有坑
                    }

                } while (true);
     
                if (match === true) { //最大匹配
                    

                    /**
                      把找到的 标记起来
                    **/
                    arrMatch[arrLength] = { //增强可读性
                        key: match_str,
                        begin: p_star - 1,
                        end: p_end
                    };
                    arrLength += 1;

                    


                    p_star = p_end;   // 小不点直接跳过坑
                }


            }
            return arrMatch;
        }
    }

    function test(strContent, strKeys) {
        var arrMatch,
            tblRoot = treeSearch.makeTree(strKeys),
            t = new Date();
      
        arrMatch = treeSearch.search(strContent, tblRoot);
         
      
        console.log("time is: " + (new Date() - t) + "mm");
     
        
     
        console.dir(arrMatch[0]);
    }

    var s = "abcd汉能abcd"; /*(function() {
        var Things = [' ', '
', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
        var s = "";
       
        for (var i = 1000000; i >= 0; i--) {
            s += Things[parseInt(Math.random() * Things.length) % Things.length]
        };

        return s;

    })()*/

    test(s, ["汉能",  "abd"]);
View Code
原文地址:https://www.cnblogs.com/dhsz/p/6564243.html