DFA算法 处理屏蔽词库

春节之后,回来就连着上班,没休息过来那.简单整下吧。

这里是lua实现的。直接上代码。

--敏感词库转化关键词 dfa算法处理屏蔽词库
require "sensitive_words"   ---词库

local SensitiveWordsUtil = class('SensitiveWordsUtil')

function SensitiveWordsUtil:ctor()
    self:createTree()
end

--树节点创建
function SensitiveWordsUtil:createNode(c,flag,nodes)
    local node = {}
    node.c = c or nil           --字符
    node.flag = flag or 0       --是否结束标志,0:继续,1:结尾
    node.nodes = nodes or {}    --保存子节点
    return node
end

--初始化树结构
function SensitiveWordsUtil:createTree()
    self.rootNode = self:createNode('R')  --根节点  
    for i=1,#sensitive_words do
        local chars = self:getCharArray(sensitive_words[i])
        if #chars > 0 then
            self:insertNode(self.rootNode,chars,1)
        end
    end

end

--插入节点
function SensitiveWordsUtil:insertNode(node,cs,index)
    local n = self:findNode(node,cs[index])
    if n == nil then
        n = self:createNode(cs[index])
        table.insert(node.nodes,n)
    end

    if index == #cs then
        n.flag = 1
    end

    index = index + 1
    if index <= #cs then
        self:insertNode(n,cs,index)
    end
end

--节点中查找子节点
function SensitiveWordsUtil:findNode(node,c)
    local nodes = node.nodes
    local rn = nil
    for i,v in ipairs(nodes) do
        if v.c == c then
            rn = v
            break
        end
    end
    return rn
end

--字符串转换为字符数组
function SensitiveWordsUtil:getCharArray(str)
    str = str or ""
    local array = {}
    local len = string.len(str)
    while str do
        local fontUTF = string.byte(str,1)

        if fontUTF == nil then
            break
        end

        --lua中字符占1byte,中文占3byte
        if fontUTF > 127 then 
            local tmp = string.sub(str,1,3)
            table.insert(array,tmp)
            str = string.sub(str,4,len)
        else
            local tmp = string.sub(str,1,1)
            table.insert(array,tmp)
            str = string.sub(str,2,len)
        end
    end
    return array
end

--将字符串中敏感字用*替换返回
function SensitiveWordsUtil:warningStrGsub(inputStr)
    local chars = self:getCharArray(inputStr)
    local index = 1
    local node = self.rootNode
    local word = {}

    while #chars >= index do
        --遇空格节点树停止本次遍历[*** -> ******]
        if chars[index] ~= ' ' then
            node = self:findNode(node,chars[index])
        end

        if node == nil then
            index = index - #word 
            node = self.rootNode
            word = {}
        elseif node.flag == 1 then
            table.insert(word,index)
            for i,v in ipairs(word) do
                chars[v] = '*'
            end
            node = self.rootNode
            word = {}
        else
            table.insert(word,index)
        end
        index = index + 1
    end

    local str = ''
    for i,v in ipairs(chars) do
        str = str .. v
    end

    return str
end

--字符串中是否含有敏感字
function SensitiveWordsUtil:isWarningInPutStr(inputStr)
    local chars = self:getCharArray(inputStr)
    local index = 1
    local node = self.rootNode
    local word = {}

    while #chars >= index do
        if chars[index] ~= ' ' then
            node = self:findNode(node,chars[index])
        end

        if node == nil then
            index = index - #word 
            node = self.rootNode
            word = {}
        elseif node.flag == 1 then
            return true
        else
            table.insert(word,index)
        end
        index = index + 1
    end

    return false
end


return SensitiveWordsUtil

说明:
1、sensitive_words.lua是词库生成的lua文件。
可以根据提供的表格,使用脚本生成,这里不解释、

简单贴下,可以生成类似的格式(只是一个例子。可以使用更好的格式。)
sensitive_words = {} 
sensitive_words[1] = "敏感词1"
sensitive_words[2] = "敏感词2"
sensitive_words[3] = "敏感词3"

2、warningStrGsub 将字符串中敏感字用*替换返回

3、--isWarningInPutStr字符串中是否含有敏感字

 

看代码吧。网上一搜一大堆。了解原理就好。

这个比全部for循环效率高很多


测试发现,低端手机,依然会卡,所以采用 c++的方式实现一遍,比lua的效率要高。 敏感词太多的话,可以分批加载,分帧加载
posted @ 2017-02-08 15:37  骑着驴的王子  阅读(1761)  评论(0编辑  收藏  举报