public List <StringSearchMatch> FindMatches(string text) { List <StringSearchMatch> rv = new List <StringSearchMatch>(); var words = this.Words.Keys.ToArray(); Parallel.For(0, words.Length - 1, () => new List <StringSearchMatch>(), (x, loop, subList) => { var word = words[x]; object val = this.Words[word]; string searchText = text; int idx = searchText.IndexOf(word); //search for this while (idx > 0) { subList.Add(StringSearchMatch.New(idx, word, val)); searchText = searchText.Substring(idx + word.Length); idx = searchText.IndexOf(word); } return(subList); }, (x) => { rv.AddRange(x); } ); return(rv); }
/// <summary> /// if the current node has a word, we build a match to return /// </summary> /// <returns></returns> public StringSearchMatch GetWordMatch() { if (!this.CurrentNode.HasWord) { return(null); } var match = StringSearchMatch.New(this.StartingIndex, this.CurrentNode.Id, this.CurrentNode.Value); return(match); }
/// <summary> /// for the provided index position, examines the trie to see if it can handle the character, and moves through /// the trie graph until it no longer matches. returns list to account for situation where matches share a common suffix. /// </summary> /// <param name="trie"></param> /// <param name="idx"></param> /// <param name="text"></param> /// <param name="graspLengthOUT">the number of characters processed</param> /// <returns></returns> public static List <StringSearchMatch> FindMatchesAtPosition(ITrieStructure trie, int idx, string text, out int graspLengthOUT) { List <StringSearchMatch> rv = new List <StringSearchMatch>(); graspLengthOUT = 0; //basic cursor position validation int maxIndex = text.Length - 1; if (maxIndex < idx) { return(rv); } graspLengthOUT = 1;//we're at least processing 1 character var currentIdx = idx; var currentNode = trie.Root; var currentChar = text[currentIdx]; //do the first test in the loop currentNode = currentNode[currentChar]; if (currentNode == null) { return(rv); } var queue = new Queue <Tuple <int, char, ITrieNode> >(); //define function to increment position, and update currentIdx, currentChar, and queue it up //implicit is the currentNode position has ALREADY been incremented at this point Func <bool> enqueue = () => { //get the next char currentIdx++; //validate position if (maxIndex < currentIdx) { return(false); } currentChar = text[currentIdx]; queue.Enqueue(new Tuple <int, char, ITrieNode>(currentIdx, currentChar, currentNode)); return(true); }; enqueue(); while (queue.Count > 0) { var tuple = queue.Dequeue(); currentNode = tuple.Item3; currentChar = tuple.Item2; currentIdx = tuple.Item1; //if we're matching, return it if (currentNode.HasWord) { var match = StringSearchMatch.New(currentIdx - 1 - currentNode.Id.Length, currentNode.Id, currentNode.Value); rv.Add(match); //update grasp length var matchGraspLength = match.Word.Length; if (graspLengthOUT < matchGraspLength) { graspLengthOUT = matchGraspLength; } } //does the trie even handle (aka lift, bro) this particular character? currentNode = currentNode[currentChar]; if (currentNode != null) { enqueue(); } } return(rv); }