JD2022-TU1/main/tools/apps/JDSongConverter/EvaluateExpression.cs

114 lines
3.2 KiB
C#

using System;
using System.Text.RegularExpressions;
using System.Collections.Generic;
namespace JDSongConverter
{
/// <summary>
/// Evaluate an expression containing text mixed with place holders.
/// </summary>
public class EvaluateExpression
{
private static Regex _regex = new Regex(@"\$\{(?<keyName>[\w]+)\}");
private MatchEvaluator _evaluator;
private Stack<string> _keysStack;
private IDictionary<string, string> _definitions;
#region Constructor
public EvaluateExpression(IDictionary<string, string> definitions)
{
_evaluator = new MatchEvaluator(Evaluator);
_keysStack = new Stack<string>();
_definitions = definitions;
}
#endregion
#region Public Methods
/// <summary>
/// Evaluate given expressions.
/// Need constant definition in parameter, and if used environment variable have to be
/// expanded.
/// </summary>
public static string Do(string expression, IDictionary<string, string> 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;
}
/// <summary>
/// Indicates an expression is fully evaluated.
/// </summary>
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
}
}