public static string Expand(this string source, params string[] args) { var output = source; var tokens = new List <string>(); var pattern = new Regex(_patternStyle.TokenMatchPattern, RegexOptions.IgnoreCase); var calls = new Stack <string>(); string callingToken = null; while (pattern.IsMatch(output)) { foreach (Match match in pattern.Matches(output)) { var token = _patternStyle.TokenReplaceFilter(match.Value); var tokenIndex = 0; if (!tokens.Contains(token)) { tokens.Add(token); tokenIndex = tokens.Count - 1; } else { tokenIndex = tokens.IndexOf(token); } output = Regex.Replace(output, _patternStyle.OutputFilter(match.Value), "{" + tokenIndex + "}"); } } var newArgs = new List <string>(); foreach (var arg in args) { var newArg = arg; var tokenPattern = new Regex(_patternStyle.TokenFilter(string.Join("|", tokens))); while (tokenPattern.IsMatch(newArg)) { foreach (Match match in tokenPattern.Matches(newArg)) { var token = _patternStyle.TokenReplaceFilter(match.Value); if (calls.Contains(string.Format("{0}:{1}", callingToken, token))) { throw new CircularReferenceException(string.Format("Circular Reference Detected for token '{0}'.", callingToken)); } calls.Push(string.Format("{0}:{1}", callingToken, token)); callingToken = token; newArg = Regex.Replace(newArg, _patternStyle.OutputFilter(match.Value), args[tokens.IndexOf(token)]); } } newArgs.Add(newArg); } return(string.Format(output, newArgs.ToArray())); }
private static string Explode(this string source, Regex pattern, PatternStyle patternStyle, Func <string, string> expansionFactory, TreeNode <string> parent) { var output = source; while (output.HasChildren(pattern)) { foreach (Match match in pattern.Matches(source)) { var child = match.Value; var token = patternStyle.TokenReplaceFilter(match.Value); var thisNode = parent.Children.Add(token); // if we have already encountered this token in this call tree, we have a circular reference if (thisNode.CallTree.Contains(token)) { throw new CircularReferenceException(string.Format("Circular Reference Detected for token '{0}'. Call Tree: {1}->{2}", token, string.Join("->", thisNode.CallTree.ToArray().Reverse()), token)); } // expand this match var expandedValue = expansionFactory(token); // Replace the match with the expanded value child = Regex.Replace(child, patternStyle.OutputFilter(match.Value), expandedValue); // Recursively expand the child until we no longer encounter nested tokens (or hit a circular reference) child = child.Explode(pattern, patternStyle, expansionFactory, thisNode); // finally, replace the match in the output with the fully-expanded value output = Regex.Replace(output, patternStyle.OutputFilter(match.Value), child); } } return(output); }
private static string Explode(this string source, Regex pattern, PatternStyle patternStyle, Func<string, string> expansionFactory, TreeNode<string> parent) { var output = source; while (output.HasChildren(pattern)) { foreach (Match match in pattern.Matches(source)) { var child = match.Value; var token = patternStyle.TokenReplaceFilter(match.Value); var thisNode = parent.Children.Add(token); // if we have already encountered this token in this call tree, we have a circular reference if (thisNode.CallTree.Contains(token)) throw new CircularReferenceException(string.Format("Circular Reference Detected for token '{0}'. Call Tree: {1}->{2}", token, string.Join("->", thisNode.CallTree.ToArray().Reverse()), token)); // expand this match var expandedValue = expansionFactory(token); // Replace the match with the expanded value child = Regex.Replace(child, patternStyle.OutputFilter(match.Value), expandedValue); // Recursively expand the child until we no longer encounter nested tokens (or hit a circular reference) child = child.Explode(pattern, patternStyle, expansionFactory, thisNode); // finally, replace the match in the output with the fully-expanded value output = Regex.Replace(output, patternStyle.OutputFilter(match.Value), child); } } return output; }