xingd.net

.net related techonology
posts - 54, comments - 601, trackbacks - 4, articles - 2

(再发).NET脏字过滤算法

Posted on 2008-01-31 21:57 xingd 阅读(2608) 评论(17)  编辑 收藏 所属分类: Framework
参见 http://www.cnblogs.com/xingd/archive/2008/01/23/1050443.html

感谢sumtech的回复和讨论,原本的效率已经足够网站实用了,虽然也想到一些改进方法,但是一直懒得去做。sumtech通过邮件跟我讨论,我也终于抽了时间做了改进,改进后的算法效率比原先的算法提高了400%,也就是仅需要原来的1/5时间。

算法关键是将两个BitArray合并成了byte[char.MaxValue],其中7个bit用来判断前7个字符,另一个bit判断其他字符。并且增加了minWordLength和charCheck,用来过滤过短的判断,以及仅有一个字符时的快速判断。

使用的数据:

private HashSet<string> hash = new HashSet<string>();
private byte[] fastCheck = new byte[char.MaxValue];
private BitArray charCheck = new BitArray(char.MaxValue);
private int maxWordLength = 0;
private int minWordLength = int.MaxValue;

初始化数据的代码:

foreach (string word in badwords)
{
    maxWordLength 
= Math.Max(maxWordLength, word.Length);
    minWordLength 
= Math.Min(minWordLength, word.Length);

    
for (int i = 0; i < 7 && i < word.Length; i++)
    {
        fastCheck[word[i]] 
|= (byte)(1 << i);
    }

    
for (int i = 7; i < word.Length; i++)
    {
        fastCheck[word[i]] 
|= 0x80;
    }

    
if (word.Length == 1)
    {
        charCheck[word[
0]] = true;
    }
    
else
    {
        hash.Add(word);
    }
}

判断是否包含脏字的代码:

public bool HasBadWord(string text)
{
    
int index = 0;

    
while (index < text.Length)
    {
        
if ((fastCheck[text[index]] & 1== 0)
        {
            
while (index < text.Length - 1 && (fastCheck[text[++index]] & 1== 0) ;
        }

        
if (minWordLength == 1 && charCheck[text[index]])
        {
            
return true;
        }

        
for (int j = 1; j <= Math.Min(maxWordLength, text.Length - index - 1); j++)
        {
            
if ((fastCheck[text[index + j]] & (1 << Math.Min(j, 7))) == 0)
            {
                
break;
            }

            
if (j + 1>= minWordLength)
            {
                
string sub = text.Substring(index, j + 1);

                
if (hash.Contains(sub))
                {
                    
return true;
                }        
            }
        }

        index
++;
    }

    
return false;
}

2008-02-01修订:发现Bug, 一个字符的charCheck应该放到for循环外,去掉j == 1的判断,外层的判断改为if (j + 1 > minWordLength)。

最后介绍下自己,我现任大众点评网(dianping.com)的系统架构师,自己的个人博客是www.stevenxu.com,点评网的整个开发团队即将推出团队博客,我的一些文章一般会先发到博客园和团队博客,跟据反馈修订后再发到个人博客。

PS: 现在匹配的是最小长度,并且是区分大小写的,这部分功能在脏字替换时需要实现。

Feedback

#1楼    回复  引用  查看    

2008-01-31 22:06 by jillzhang      
不错,支持一下
树是不是比较好的解决方法

#2楼    回复  引用  查看    

2008-01-31 23:31 by 周银辉      
不错不错,有空研究一下

#3楼 [楼主]   回复  引用  查看    

2008-01-31 23:46 by xingd      
@周银辉
从你的博客看出来你关注WPF挺多的。我也看过WPF,因为实际工作不用,所以没有太多实践。不过因为以前有Win32, GDI/GDI+, DirectX的底子,对WPF的实现机制还是了解的不错。

有机会多交流下WPF。

#4楼    回复  引用    

2008-02-01 00:20 by A1 [未注册用户]
既然你对这个兴趣那么大,还是搜索一下 "multi pattern string matching" 多看几篇论文再思考一下。
KMP可以不看了,BM,WM是必须的,特别是WM,它是agrep的基础算法,压缩码匹配方式的代表。
效率超过WM当然也有好几个,毕竟WM是90年代初的东西,这些新算法优势多数都是在模式数量超大、最短模式长度越长等情况下才能现象。
考虑对于脏字过滤这样的场景,实际模式数量不会太多(一般网站几百个就到顶了),单词也不会太长,所以WM算法的参考简直最大。
在我看来,匹配成功后如何操作原字符串并得到新串的方式也是很值得考究的,原因嘛,大多数人的习惯造成的。

PS:实际应用中还得考虑英文字符的大小写问题,弄得好其中还有可提高效率的方法。

#5楼    回复  引用  查看    

2008-02-01 08:45 by 留恋星空      
MARK

#6楼    回复  引用  查看    

2008-02-01 08:56 by 也许      
mark

#7楼    回复  引用    

2008-02-01 09:24 by 在线代理 [未注册用户]
只会用Regular Expression 。

特来学习。

#8楼    回复  引用  查看    

2008-02-01 09:41 by Clark Zheng      
A1的回复很专业呀

#9楼    回复  引用  查看    

2008-02-01 09:57 by WOW玩家      
收藏先

#10楼 [楼主]   回复  引用  查看    

2008-02-01 10:57 by xingd      
@A1

也不完全是因为兴趣,主要是工作需要,而且也对自己设计算法并持续改进乐在其中。我们团队里有对文本处理感兴趣的同事,我会把你提到的信息推荐给他。

谢谢!

#11楼    回复  引用    

2008-02-01 12:04 by sumtec@beijing [未注册用户]
楼主:
你的新方法我已经测过了,有Bug,会漏掉很多Match,原因未知。
我给你发了邮件,第一次发的时候发的时候,不小心直接把报告贴到邮件里面了,结果被263给截获了,说是因为keyword的原因被拒了。看来国内的邮箱挺和谐的(有传闻说和谐这个词也将要被和谐了),后来我发了一个txt附件的,不知道你能否收到。
怀疑我的邮箱已被263列入黑名单,发什么都不处理也不报告错误。

另外,建议你还是用Gmail吧,这种因为内容有keyword收不到信是非常糟糕的。比如我告诉你“他母亲的样子真的很年轻”……你就收不到啦……

P.S.:我的算法已经基本稳定,昨晚跟你说的那个“新想法”暂时还没有实施。
个人觉得目前的版本已经让我比较满意了,能够实际使用了。

#12楼 [楼主]   回复  引用  查看    

2008-02-01 12:08 by xingd      
@sumtec@beijing
的确我的新算法还没有经过足够多的测试,但是思路还算是讲清楚了。发现bug后我及时做修订。

#13楼    回复  引用  查看    

2008-02-01 15:14 by 书生多命贱      
楼主能说下思路,或者写个注释吗??我看的不是太明白。

#14楼 [楼主]   回复  引用  查看    

2008-02-01 15:16 by xingd      
@书生多命贱
请把不明白的点讲一下。

如果附近有可以一起讨论的同事/同学,就更方便了。

#15楼    回复  引用    

2008-02-01 16:14 by 天龙八部 [未注册用户]
直接用REPLACE``

#16楼    回复  引用  查看    

2008-02-02 10:27 by 蛙蛙池塘      
大众点评网,做的8错,呵呵,口碑网是你们的竞争对手吧

#17楼    回复  引用  查看    

2008-07-22 20:45 by 逖靖寒      
@A1

标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  博客园首页

  新闻频道

  社区

  小组

  博问

  网摘

  闪存

  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2008-02-01 20:21 编辑过
成果网帮您增加网站收入


相关链接: