C# 如何在RPN(反向波兰符号)中使用IF-ELSE?
我已经完成了一个RPN类来计算最终用户输入喜欢的字符串 “1.0+3/2-tan(45)/(1+1)+sin(30)*abs(-1)+abs(-10)” 然后,我想解析条件语句和多参数函数,如“if(1>2,3/3,2*1)”,“max(1,2,3,4)” 那么,我的问题是如何在RPN中使用IF-ELSE 这是我的代码:对于C# 如何在RPN(反向波兰符号)中使用IF-ELSE?,c#,math,rpn,C#,Math,Rpn,我已经完成了一个RPN类来计算最终用户输入喜欢的字符串 “1.0+3/2-tan(45)/(1+1)+sin(30)*abs(-1)+abs(-10)” 然后,我想解析条件语句和多参数函数,如“if(1>2,3/3,2*1)”,“max(1,2,3,4)” 那么,我的问题是如何在RPN中使用IF-ELSE 这是我的代码:对于如果(1>2,3/3,2*1)您首先从右到左计算三个参数,并将它们的结果推送到堆栈上,使其看起来像这样: top-of-stack->false
如果(1>2,3/3,2*1)
您首先从右到左计算三个参数,并将它们的结果推送到堆栈上,使其看起来像这样:
top-of-stack->false
1
2
然后,如果
将在RPN引擎中实现(伪代码):
对于多参数函数,不需要特殊处理。只需计算并推送所有参数(通常是从右向左)。函数的实现应该弹出所需数量的参数,然后推送其结果(如果有)。对于if(1>2,3/3,2*1)
您应该首先从右到左计算这三个参数,并将其结果推送到堆栈上,使其看起来像这样:
top-of-stack->false
1
2
然后,如果
将在RPN引擎中实现(伪代码):
对于多参数函数,不需要特殊处理。只需计算并推送所有参数(通常是从右向左)。函数的实现应该弹出所需数量的参数,然后推送它的结果(如果有)。我尝试解析多参数函数,例如if\Max before RPN.parse()
公共类多参数函数解析器
{
public readonly List Funcs=新列表{“IF”,“MAX”};
公共字符串解析(字符串表达式)
{
while(IsFunction(exp,out var index,out var funcName))//
{
var parameters=GetParameters(exp、index、funcName、out-var-before、out-var-after);
var list=GetParameterList(参数);
var值=评估(列表、函数名);
exp=$“{before}({value}){after}”;
}
返回经验;
}
///
///Exp是否包含函数?
///
///
///
///
///
私有bool-IsFunction(字符串exp、out-int索引、out-string-funcName)
{
指数=-1;
funcName=“”;
foreach(Funcs中的var func)
{
var idx=exp.IndexOf($“{func}”(,StringComparison.CurrentCultureIgnoreCase);
如果(idx==-1 | | idx+3>=经验长度-1)
继续;
指数=idx;
funcName=func;
打破
}
返回索引!=-1&&index+3rightCount)
结果+=c;
其他的
打破
索引++;
}
after=exp.Substring(索引+1,exp.Length-index-1);
返回结果;
}
///
///解析要列出的参数字符串。
///
///最大值(1,-1),1,0
///{“MAX(1,-1)”,“1”,“0”}
私有静态列表GetParameterList(字符串exp)
{
变量计数=扩展长度;
对于(变量i=count-1;i>-1&&exp.Length>0;i--)
{
var c=exp[i];
如果(c!=',')
继续;
var after=exp.Substring(i+1);
var before=exp.Substring(0,i);
如果(在.Count(a=>a='(').Equals(在.Count(a=>a=')))之后)
{
exp=before+'#'+after;
}
}
var results=exp.Split('#').ToList();
返回结果;
}
私有静态双重求值(列表参数、字符串名称)
{
if(funcName.Equals(“MAX”,StringComparison.CurrentCultureIgnoreCase))
返回EvaluateMax(参数);
if(funcName.Equals(“if”,StringComparison.CurrentCultureIgnoreCase))
返回EvaluateIF(参数);
返回0;
}
私有静态双重求值IF(列表参数)
{
if(parameters==null | | parameters.Count!=3)
抛出新异常(“EvaluateIF parameters.Count()!=3”);
var results=新列表();
foreach(参数中的var参数)
{
var rpn=新的rpn();
解析(参数);
var obj=rpn.Evaluate();
if(obj==null)
{
抛出新异常(“EvaluateIF Not Number!”);
}
if(obj.ToString().Equals(“true”,StringComparison.CurrentCultureIgnoreCase))
{
结果:增加(1);
}
else if(obj.ToString().Equals(“false”,StringComparison.CurrentCultureIgnoreCase))
{
结果:添加(-1);
}
其他的
{
if(double.TryParse(obj.ToString(),out var d))
结果:添加(d);
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;
}
}