я пытаюсь разобрать многопараметрическую функцию, например if \ Max перед RPN.Parse ()
public class MultiParameterFunctionParser
{
public readonly List<string> Funcs = new List<string> {"IF", "MAX"};
public string Parse(string exp)
{
while (IsFunction(exp,out var index,out var funcName))//
{
var parameters = GetParameters(exp, index, funcName, out var before, out var after);
var list = GetParameterList(parameters);
var value = Evaluate(list, funcName);
exp= $"{before}({value}){after}";
}
return exp;
}
/// <summary>
/// Is Exp Contains a function?
/// </summary>
/// <param name="exp"></param>
/// <param name="index"></param>
/// <param name="funcName"></param>
/// <returns></returns>
private bool IsFunction(string exp, out int index, out string funcName)
{
index = -1;
funcName = "";
foreach (var func in Funcs)
{
var idx = exp.IndexOf($"{func}(", StringComparison.CurrentCultureIgnoreCase);
if (idx == -1 || idx + 3 >= exp.Length - 1)
continue;
index = idx;
funcName = func;
break;
}
return index != -1 && index + 3 < exp.Length - 1;
}
/// <summary>
/// Get Parameters' string
/// </summary>
/// <param name="exp">8+if(12,sin(90),0)+1.2</param>
/// <param name="index">2 if's start index</param>
/// <param name="before">8+</param>
/// <param name="after">+1.2</param>
/// <returns>12,sin(90),0</returns>
private static string GetParameters(string exp,int index, string funcName, out string before, out string after)
{
before = exp.Substring(0, index);
index += funcName.Length + 1;
var leftCount = 1; // '(' count
var rightCount = 0;// ')' count
var results = "";
while (index < exp.Length && leftCount != rightCount)
{
var c = exp[index];
if (c.Equals('('))
leftCount++;
else if (c.Equals(')'))
rightCount++;
if (leftCount > rightCount)
results += c;
else
break;
index++;
}
after = exp.Substring(index + 1, exp.Length - index - 1);
return results;
}
/// <summary>
/// Parse Parameter string to list.
/// </summary>
/// <param name="exp">MAX(1,-1),1,0</param>
/// <returns>{"MAX(1,-1)","1","0"}</returns>
private static List<string> GetParameterList(string exp)
{
var count = exp.Length;
for (var i = count - 1; i > -1 && exp.Length > 0; i--)
{
var c = exp[i];
if (c != ',')
continue;
var after = exp.Substring(i + 1);
var before = exp.Substring(0,i);
if (after.Count(a => a == '(').Equals(after.Count(a => a == ')')))
{
exp = before + '#' + after;
}
}
var results = exp.Split('#').ToList();
return results;
}
private static double Evaluate(List<string> parameters, string funcName)
{
if (funcName.Equals("MAX", StringComparison.CurrentCultureIgnoreCase))
return EvaluateMax(parameters);
if (funcName.Equals("IF", StringComparison.CurrentCultureIgnoreCase))
return EvaluateIF(parameters);
return 0;
}
private static double EvaluateIF(List<string> parameters)
{
if (parameters == null || parameters.Count != 3)
throw new Exception("EvaluateIF parameters.Count()!=3");
var results = new List<double>();
foreach (var parameter in parameters)
{
var rpn = new RPN();
rpn.Parse(parameter);
var obj = rpn.Evaluate();
if (obj == null)
{
throw new Exception("EvaluateIF Not Number!");
}
if (obj.ToString().Equals("true", StringComparison.CurrentCultureIgnoreCase))
{
results.Add(1);
}
else if (obj.ToString().Equals("false", StringComparison.CurrentCultureIgnoreCase))
{
results.Add(-1);
}
else
{
if (double.TryParse(obj.ToString(), out var d))
results.Add(d);
else
throw new Exception("EvaluateIF Not Number!");
}
}
return results[0] >= 0 ? results[1] : results[2];
}
private static double EvaluateMax(IEnumerable<string> parameters)
{
var results = new List<double>();
foreach (var parameter in parameters)
{
var rpn = new RPN();
rpn.Parse(parameter);
var obj = rpn.Evaluate();
if (double.TryParse(obj.ToString(), out var d))
results.Add(d);
}
return results.Count > 0 ? results.Max() : 0;
}
}