using System; using System.Text.RegularExpressions; using System.Collections.Generic; namespace JDSongConverter { /// /// Evaluate an expression containing text mixed with place holders. /// public class EvaluateExpression { private static Regex _regex = new Regex(@"\$\{(?[\w]+)\}"); private MatchEvaluator _evaluator; private Stack _keysStack; private IDictionary _definitions; #region Constructor public EvaluateExpression(IDictionary definitions) { _evaluator = new MatchEvaluator(Evaluator); _keysStack = new Stack(); _definitions = definitions; } #endregion #region Public Methods /// /// Evaluate given expressions. /// Need constant definition in parameter, and if used environment variable have to be /// expanded. /// public static string Do(string expression, IDictionary definitions, bool expandEnvironment = false) { if (string.IsNullOrEmpty(expression)) { return expression; } EvaluateExpression context = new EvaluateExpression(definitions); string evaluatedExpression = context.Recursive(expression); return expandEnvironment ? Environment.ExpandEnvironmentVariables(evaluatedExpression) : evaluatedExpression; } /// /// Indicates an expression is fully evaluated. /// public static bool IsEvaluated(string expression) { if (string.IsNullOrEmpty(expression)) { return true; } return !_regex.IsMatch(expression); } #endregion #region Private Methods private string GetKeyName(Match match) { return (null != match) ? match.Groups["keyName"].Value : string.Empty; } private string Recursive(string expression) { try { Match match = _regex.Match(expression); if (!match.Success) { return expression; } string evaluated = _regex.Replace(expression, _evaluator); return (evaluated != expression) ? Recursive(evaluated) : evaluated; } catch (System.Exception ex) { throw new Exception("Impossible to evaluate : " + expression, ex); } } private string Evaluator(Match match) { string keyName = GetKeyName(match); string keyValue; if (!_definitions.TryGetValue(keyName, out keyValue)) { return match.Value; } if (_keysStack.Contains(keyName)) { throw new Exception(keyName + " is used in a cyclic manner"); } _keysStack.Push(keyName); string expression = Recursive(keyValue); _keysStack.Pop(); return expression; } #endregion } }