这段时间开发一个聊天室,需要使用到关键字过滤的功能,需求如下:
1.将关键字替换成“*”;
2.支持过滤HTML,例如,S<span>B</span>也要过滤掉。
原本打算使用String.Replace来实现,但是这样的话,如果关键字很多,例如1000个,用以下方式:
for(int i=0;i<1000;i++)
{
replace….
}
来实现,性能显然很低。因此,换了一种方法,用了Hashtable来提高过滤的性能。大概思路如下:
根据所有关键字建好用Hashtable数据结构,也可以理解为建立索引,之后每次过滤都用这个来进行:
例如,有以下几个关键字: SB , SX, Fuck, AB, ABC,那么用于过滤的数据结构如下:
上图中每个黑色方框代表一个hashtable,里面的字母就是hashtable的key,每个key都指向另一个hashtable,例如,第一个hashtable中就包含了3个Key,分别是S,A,F。每个关键字中的每个字符都被分散的放到hashtable中。
下面举例如何过滤
1.处理字符串 SB:第一个字母在第一级的hashtable中找到,而B也可以在S指向的Hashtable中找到,B指向的Hashtable中包括0,则,SB符合关键字,过滤掉。
2.处理字符串 SF:虽然S在第一级hashtable中可以找到,但是S指向的hashtable中没有F,所以,SF不是关键字
具体代码如下:
static class FilterWordUtil
{
static Hashtable FilterWords = new Hashtable();
public static void AddFilterWord(string word)
{
Hashtable h = FilterWords;
foreach (char c in word.ToUpper())
{
if (!h.ContainsKey(c)) h[c] = new Hashtable();
h = h[c] as Hashtable;
}
h[0] = new Hashtable();
}
static int Match(string content, int index, out StringBuilder alt)
{
content = content.ToUpper();
alt = new StringBuilder();
bool filterChar = true;
Hashtable h = FilterWords;
int i = index;
for (; i < content.Length; i++)
{
char c = content[i];
switch (c)
{
case '<':
{
filterChar = false;
break;
}
case '>':
{
filterChar = true;
break;
}
case ' ':
{
break;
}
default:
{
if (filterChar)
{
if (h.ContainsKey(c))
{
h = h[c] as Hashtable;
c = '*';
}
else
{
if (!h.ContainsKey(0)) return -1;
}
}
break;
}
}
alt.Append(c);
if (h.ContainsKey(0)) return i;
}
return h.ContainsKey(0) ? i : -1;
}
public static String Filter(string content)
{
lock (FilterWords)
{
StringBuilder result = new StringBuilder();
bool filterChar = true;
for (int i = 0; i < content.Length; i++)
{
char c = content[i];
switch (c)
{
case '<':
{
filterChar = false;
break;
}
case '>':
{
filterChar = true;
break;
}
default:
{
if (filterChar)
{
StringBuilder temp;
int fi = Match(content, i, out temp);
if (fi != -1)
{
i = fi;
result.Append(temp);
continue;
}
}
break;
}
}
result.Append(c);
}
return result.ToString();
}
}
}
测试代码:
1: //添加关键字
2: FilterWordUtil.AddFilterWord("SB");
3: FilterWordUtil.AddFilterWord("SX");
4: FilterWordUtil.AddFilterWord("fuck");
5: FilterWordUtil.AddFilterWord("fuck you");
6: FilterWordUtil.AddFilterWord("天朝");
7: //过滤
8: string new_html = FilterWordUtil.Filter("你是SB,天<span>朝</span>");
9: Console.WriteLine(new_html);
过滤效果如下:
看到这里,有些读者要担心了,用了这么多的hashtable,会不会占用很多内存?当时也考虑过这问题,测试了1000多个关键字,建数据结构后,内存大概增加了几M,还不算太多。
转载至http://www.cnblogs.com/lucc/archive/2011/06/30/2093898.html