使用Hashtable实现简单的关键字过滤
这段时间开发一个聊天室,需要使用到关键字过滤的功能,需求如下:
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不是关键字
具体代码如下:
1: static class FilterWordUtil
2: {
3: static Hashtable FilterWords = new Hashtable();
4:
5: public static void AddFilterWord(string word)
6: {
7: Hashtable h = FilterWords;
8: foreach (char c in word.ToUpper())
9: {
10: if (!h.ContainsKey(c)) h[c] = new Hashtable();
11: h = h[c] as Hashtable;
12: }
13: h[0] = new Hashtable();
14: }
15:
16: static int Match(string content, int index, out StringBuilder alt)
17: {
18: content = content.ToUpper();
19: alt = new StringBuilder();
20: bool filterChar = true;
21:
22: Hashtable h = FilterWords;
23: int i = index;
24: for (; i < content.Length; i++)
25: {
26: char c = content[i];
27: switch (c)
28: {
29: case '<':
30: {
31: filterChar = false;
32: break;
33: }
34: case '>':
35: {
36: filterChar = true;
37: break;
38: }
39: case ' ':
40: {
41: break;
42: }
43: default:
44: {
45: if (filterChar)
46: {
47: if (h.ContainsKey(c))
48: {
49: h = h[c] as Hashtable;
50: c = '*';
51: }
52: else
53: {
54: if (!h.ContainsKey(0)) return -1;
55: }
56: }
57: break;
58: }
59: }
60: alt.Append(c);
61: if (h.ContainsKey(0)) return i;
62: }
63: return h.ContainsKey(0) ? i : -1;
64: }
65:
66: public static String Filter(string content)
67: {
68: lock (FilterWords)
69: {
70: StringBuilder result = new StringBuilder();
71: bool filterChar = true;
72:
73: for (int i = 0; i < content.Length; i++)
74: {
75: char c = content[i];
76: switch (c)
77: {
78: case '<':
79: {
80: filterChar = false;
81: break;
82: }
83: case '>':
84: {
85: filterChar = true;
86: break;
87: }
88: default:
89: {
90: if (filterChar)
91: {
92: StringBuilder temp;
93: int fi = Match(content, i, out temp);
94: if (fi != -1)
95: {
96: i = fi;
97: result.Append(temp);
98: continue;
99: }
100: }
101: break;
102: }
103: }
104: result.Append(c);
105: }
106:
107: return result.ToString();
108: }
109: }
110: }
测试代码:
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,还不算太多。