/// <summary> /// Given a dictionary of substitutions creates a new graph of nodes for the finite state /// automata used when pattern matching for substitutions. /// </summary> /// <param name="substitutions">The dictionary of substitutions where the key is the search item and the value is what to replace it with.</param> public void CreateSubstitutionGraph(Dictionary<string, string> substitutions) { this.FsaGraph = new AimlBot.Normalize.Utils.FsaNode(0); foreach (string key in substitutions.Keys) { this.FsaGraph.Add(key, substitutions[key]); } }
/// <summary> /// Given a dictionary of substitutions creates a new graph of nodes for the finite state /// automata used when pattern matching for substitutions. /// </summary> /// <param name="substitutions">The dictionary of substitutions where the key is the search item and the value is what to replace it with.</param> public void CreateSubstitutionGraph(Dictionary <string, string> substitutions) { this.FsaGraph = new AimlBot.Normalize.Utils.FsaNode(0); foreach (string key in substitutions.Keys) { this.FsaGraph.Add(key, substitutions[key]); } }
/// <summary> /// Adds a new path to the graph of child nodes /// </summary> /// <param name="path">The path to add this node</param> /// <param name="position">The position within the path array identifying the key to add</param> /// <param name="Replace">The string to be used as the replacement if the node is matched /// by the search algorithm.</param> /// <returns>The newly added node</returns> private FsaNode AddChild(char[] path, int position, string Replace) { if (position < path.Length) { if (this.Children.ContainsKey(path[position])) { // check we've not arrived at an existing leaf node if (((FsaNode)this.Children[path[position]]).Replace.Length == 0) { // nope... so carry on return(this.Children[path[position]].AddChild(path, (position + 1), Replace)); } else { // must have been passed either: // // * a duplicate path // * a path that starts with an existing match // // throw helpful exception so the user knows what they need to change. StringBuilder duplicatePath = new StringBuilder(); for (int i = 0; i < path.Length; i++) { duplicatePath.Append(path[i]); } StringBuilder existingPath = new StringBuilder(); for (int i = 0; i < position + 1; i++) { existingPath.Append(path[i]); } throw new NormalizationException(String.Format(CultureInfo.CurrentCulture, rm.GetString("DuplicateSubstitution"), duplicatePath.ToString(), Replace, existingPath.ToString(), ((FsaNode)this.Children[path[position]]).Replace)); } } else { // no matching child node so create one and continue FsaNode child = new FsaNode(position + 1); this.Children.Add(path[position], child); return(child.AddChild(path, (position + 1), Replace)); } } else { // we've arrived at a leaf node so set the replacement and return this node this.Replace = Replace; return(this); } }
/// <summary> /// Adds a new path to the graph of child nodes /// </summary> /// <param name="path">The path to add this node</param> /// <param name="position">The position within the path array identifying the key to add</param> /// <param name="Replace">The string to be used as the replacement if the node is matched /// by the search algorithm.</param> /// <returns>The newly added node</returns> private FsaNode AddChild(char[] path, int position, string Replace) { if (position < path.Length) { if (this.Children.ContainsKey(path[position])) { // check we've not arrived at an existing leaf node if (((FsaNode)this.Children[path[position]]).Replace.Length == 0) { // nope... so carry on return this.Children[path[position]].AddChild(path, (position + 1), Replace); } else { // must have been passed either: // // * a duplicate path // * a path that starts with an existing match // // throw helpful exception so the user knows what they need to change. StringBuilder duplicatePath = new StringBuilder(); for (int i = 0; i < path.Length; i++) { duplicatePath.Append(path[i]); } StringBuilder existingPath = new StringBuilder(); for (int i = 0; i < position + 1; i++) { existingPath.Append(path[i]); } throw new NormalizationException(String.Format(CultureInfo.CurrentCulture, rm.GetString("DuplicateSubstitution"), duplicatePath.ToString(), Replace, existingPath.ToString(), ((FsaNode)this.Children[path[position]]).Replace)); } } else { // no matching child node so create one and continue FsaNode child = new FsaNode(position + 1); this.Children.Add(path[position], child); return child.AddChild(path, (position + 1), Replace); } } else { // we've arrived at a leaf node so set the replacement and return this node this.Replace = Replace; return this; } }
/// <summary> /// A recursive function that processes the input array and compares it with the contents of the /// FsaNode graph. If a match is found then a replacement is made and added to the result, otherwise /// the unmatched input is added to the result instead. /// </summary> /// <param name="input">Array of chars to have substitutions</param> /// <param name="node">The root node of the FSANode graph containing the substitution definitions</param> /// <param name="result">To hold the string resulting from the substitutions</param> private void Sub(char[] input, FsaNode node, StringBuilder result) { if (node.Children.ContainsKey(input[this.counter])) { // we have a match FsaNode child = node.Children[input[this.counter]]; if (child.Replace.Length > 0) { // we have a replacement so add it to the result result.Append(child.Replace); return; } else { // no replacement so see if the next character can be matched this.counter++; if (this.counter < input.Length) { this.Sub(input, child, result); } else { // we must be at the end of the array this.counter -= node.Depth+1; result.Append(input[this.counter]); } return; } } else { // no match so "rewind" the counter to the correct point in the array // and add the unmatched character to the result. this.counter -= node.Depth; result.Append(input[this.counter]); return; } }