xingd.net

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

忽略大小写的.NET脏字过滤算法

Posted on 2008-02-04 19:37 xingd 阅读(1769) 评论(17)  编辑 收藏 所属分类: Framework
重复的内容就不再重复了,参考http://www.cnblogs.com/xingd/archive/2008/02/01/1061800.html

除了实现忽略大小写外,其他方面的性能也做了一些改进,主要借助下面的类,StringSegement,实现了大小写无关的比较和GetHashCode,同时避免了Substring的调用。

public class StringSegment
{
    
private string original;
    
private int offset = 0;
    
private int length = 0;

    
public StringSegment(string s)
    {
        
this.original = s;
        
this.length = original.Length;
    }

    
public void Slice(int offset, int length)
    {
        
this.offset = offset;
        
this.length = length;
    }

    
public override bool Equals(object obj)
    {
        StringSegment sg 
= obj as StringSegment;
        
return sg != null && sg.length == this.length && string.Compare(this.original, this.offset, sg.original, sg.offset, this.length, true== 0;
    }

    
public override int GetHashCode()
    {
        
// call char.tolower and calculate hash code
    }
}

GetHashCode的实现完全参考string的实现,就不重复了,挺长的一段。

另外,对于特征判断的数据,规划为64k x 4 bytes,也就是每char给4 bytes特征数据,如果有算法改进,只要在这4 bytes里重新规划,现在的定义如下:

[StructLayout(LayoutKind.Explicit, Size = 32)]
internal struct FastCheckFlag
{
    [FieldOffset(
0)]
    
public byte occur;    // 1st~8th char occurrence
    [FieldOffset(8)]
    
public byte length;   // 2~9 word length begin with this char
    [FieldOffset(16)]
    
public byte rlength; // 2~9 word length end with this char (reverse length);
    [FieldOffset(24)]
    
public bool single; // single char bad words
    [FieldOffset(25)]
    
public bool last;    // last occurrence
    [FieldOffset(26)]
    
public byte occurParity;  // 9th~ occurrence parity flag
    [FieldOffset(28)]
    
public byte lengthParity; // 10~ length parity flag
    [FieldOffset(30)]
    
public byte rlengthParity; // 10~ rlength parity flag
}

 另外在初始化数据的时候,取字符的大小写同时处理,例如:

if (word.Length == 1)
{
    fastCheck[
char.ToLower(word[0])].single = true;
    fastCheck[
char.ToUpper(word[0])].single = true;
}


完整的代码就不贴了,经过实际测试,效率还是很不错。鼓励读者按照我的几篇文章自己写具体的代码,以及替换的实现。有问题请留评论,我会逐一回复,但是直接要代码的就免了。

索引:
我最早看到的文章,包含脏字典和测试代码,有string和regex两种实现。http://www.cnblogs.com/goody9807/archive/2006/09/12/502094.html
我的第一篇文章,区分大小写,两个BitArray优化,主要介绍思路。 http://www.cnblogs.com/xingd/archive/2007/09/26/906013.html
我整理过的实现,区分大小写,同第一篇,我们正在用的版本。http://www.cnblogs.com/xingd/archive/2008/01/23/1050443.html
第一次改进,区分大小写,扩展到了8个字符判断。http://www.cnblogs.com/xingd/archive/2008/01/31/1060425.html
第二次改进,区分大小写,增加了长度判断和结束符。http://www.cnblogs.com/xingd/archive/2008/02/01/1061800.html
最终版本,不区分大小写,消除Substring的代价,本文。

 

Feedback

#1楼    回复  引用    

2008-02-04 23:12 by 图片 [未注册用户]
不错顶下

#2楼    回复  引用  查看    

2008-02-04 23:15 by 郝婧      
嗯 写的挺好 学习一下

#3楼    回复  引用    

2008-02-05 00:18 by evanescencex [未注册用户]
楼主的思路不错,收藏了,慢慢看。

#4楼    回复  引用    

2008-02-05 01:55 by 胡新 [未注册用户]
--引用--------------------------------------------------
evanescencex: 祝你 新年快了 。
--------------------------------------------------------

#5楼    回复  引用  查看    

2008-02-05 03:11 by fox23      
有趣,收藏一个

#6楼    回复  引用  查看    

2008-02-05 08:34 by 学者      
呵呵 有趣 都在比啊
有气氛!TTMP算法 也在写

#7楼    回复  引用    

2008-04-10 10:25 by fqf [未注册用户]
初学者请教一个问题。我学习了你分享的这几篇好文,也尝试自己组合弄弄,便宜过程中发现一个错误一直想不到解决办法:
###############################

编译器错误信息: CS0246: 找不到类型或命名空间名称“HashSet”(是否缺少 using 指令或程序集引用?)

源错误:



行 17: public class ClearBadword
行 18: {
行 19: private HashSet<string> hash = new HashSet<string>();
行 20: private byte[] fastCheck = new byte[char.MaxValue];
行 21: private byte[] fastLength = new byte[char.MaxValue];



###############################


我的代码前面部分是这样写的:
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
/// <summary>
/// ClearBadword 的摘要说明
/// </summary>
public class ClearBadword
{
private HashSet<string> hash = new HashSet<string>();
private byte[] fastCheck = new byte[char.MaxValue];
private byte[] fastLength = new byte[char.MaxValue];
private BitArray charCheck = new BitArray(char.MaxValue);
private BitArray endCheck = new BitArray(char.MaxValue);
private int maxWordLength = 0;
private int minWordLength = int.MaxValue;



========
请指教 谢谢

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

2008-04-10 10:51 by xingd      
@fqf
HashSet是.NET 3.5中新增的,如果使用.NET 2.0,可以用Dictionary<string, object>代替。

#9楼    回复  引用    

2008-04-10 14:29 by fqf [未注册用户]
谢谢博主的回答。

我的是2.0的 所以将原来地方修改了3处:
1;
private Dictionary<string, object> hash = new Dictionary<string, object>();

2;
else
{
fastLength[word[0]] |= (byte)(1 << (Math.Min(7, word.Length - 2)));
endCheck[word[word.Length - 1]] = true;
hash.Add(word, null);
//hash.Add(word);
}

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


不知道这样是否正确,谢谢!


另外,能否麻烦也贴出这个部分内部代码分享一下呢?谢谢。

public override int GetHashCode()
{
// call char.tolower and calculate hash code
}

------------------------
实话,我以前是做java的,现在为了做自己一个网站,考虑服务空间问题,决定学.net来开发,一边学一边用。现在网站对屏蔽敏感词非常必要,而有目的的搜索到你这篇关于高效率过滤的技术文章,内心真的很想一下子能学到并应用进去。可惜自己刚刚接触,无法一时理解大师级的编程精髓,所以,如果博主乐意的话,希望能得到更多的帮助,谢谢! 个人邮箱为 mail@fqf.cn

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

2008-04-10 15:22 by xingd      
@fqf
GetHashCode的代码已发到你的邮箱

#11楼    回复  引用    

2008-04-10 21:21 by fqf [未注册用户]
非常谢谢 已收到

#12楼    回复  引用    

2008-04-10 21:28 by fqf [未注册用户]
终于学会使用了 运行成功 非常感谢博主!!

#13楼    回复  引用  查看    

2008-05-05 23:28 by 黑鹰      
博主可否给我发一份2.0的,多谢hiying#163.com

#14楼    回复  引用  查看    

2008-05-29 00:08 by Kevan      
楼主,我也要一份啊。。。

#15楼    回复  引用    

2008-06-19 17:33 by zzzzz [未注册用户]
能否再讲下实现的算法啊,通俗一点的,看的不明白。

#16楼    回复  引用  查看    

2008-07-22 17:27 by 逖靖寒      
看了楼主的这一些列文章,不错。但是缺少注释,可能新手不容易理解哈。

#17楼    回复  引用    

2008-08-20 19:15 by reddust [未注册用户]
楼主看下,“世纪中国基金会”这个词可以查到,变成“<p>世纪中国基金会世纪中国基金会</p>”就查不到了?是bug吗?