Boyer-Moore算法的c#实现
下午在博客园看到阮一峰的Boyer-Moore字符串搜索算法 ,觉得挺有意思。也就照着文章,用c#实现了。一开始看了几遍,一些名词有点迷糊。
比如“搜索词中的上一次出现位置”,应该是“如果有多个坏字符,指搜索词的最后坏字符的一个位置”,比如“好后缀规则”里的一些地方说的让人摸不着
头脑。后来一边写代码,一边理解。才大至明白了。
View Code
using System; using System.Collections.Generic; using System.Text; namespace Boyer_Moore { class BoyerMooreSearch { public string searchword{get;private set;} /// <summary> /// 坏字符规则表 /// </summary> Dictionary<char, List<int>> dictCharIndex = new Dictionary<char, List<int>>(); /// <summary> /// 好后缀规则表 /// </summary> Dictionary<string, string> dictPrefixIndex = new Dictionary<string, string>(); public BoyerMooreSearch(string sword) { searchword = sword; if (string.IsNullOrEmpty(searchword)) { throw new ArgumentNullException(); } for (int i = 0; i < searchword.Length; i++) { char ch = searchword[i]; if (dictCharIndex.ContainsKey(ch)) { dictCharIndex[ch].Add(i); } else { dictCharIndex.Add(ch, new List<int>() { i }); } string str = searchword.Substring(0, i + 1); dictPrefixIndex.Add(str, ""); } } public int Serach(string content) { if(string.IsNullOrEmpty(content)) { throw new ArgumentNullException(); } int offset = 0; string prefix = ""; string goodsuffix = "" ; for (int i = 0; i < content.Length; i += offset) { if (i + searchword.Length > content.Length) { break; } prefix = ""; goodsuffix = ""; int gsoffset = 0; bool finded = true; for (int j = searchword.Length - 1; j > -1; j--) { char ch = searchword[j]; char srcch = content[i + j]; if (srcch == ch) { goodsuffix = searchword.Substring(j, searchword.Length - j); if (dictPrefixIndex.ContainsKey(goodsuffix)) { prefix = goodsuffix; } } else { finded = false; //后移位数 = 坏字符的位置 - 搜索词中的上一次出现位置(上一次位置:如果有多个坏字符,指搜索词的最后坏字符的一个位置) if (dictCharIndex.ContainsKey(srcch)) { offset = j - dictCharIndex[srcch][dictCharIndex[srcch].Count-1]; } else { offset = j + 1; } //当有好后缀时 if (goodsuffix != "") { //后移位数 = 好后缀的位置 - 搜索词中的上一次出现位置.如果不存在。则上一次位置为-1 //如果有后缀在前缀位置 if (prefix != "") { gsoffset = searchword.Length - prefix.Length; } else { gsoffset = searchword.Length; } } //比较谁的位移大 if (gsoffset > offset) { offset = gsoffset; } break; } } if (finded) { return i; } } return -1; } } }