此文基于https://www.codeproject.com/Articles/5875/C-Expression-Parser-using-RPN 修改,大部分源码皆来自于此页面
本文增加三角函数计算。
以下贴出调用
1、单次计算
string strExpression = "A*1.0+Sin(A*1.2-B)-COS(C)+3/2-TAN(45)/(1+F)+LOG(G)-1.5*D-abs(0-9)";
Dictionary<string, double> keyValuePairs1 = new Dictionary<string, double>()
{
{"A",1.23 },{"B",1.23},{"C",1.23},{"F",1.23},{"G",1.23},{"D",1.23},
};
using (Tokenizer Tokenizer = new Tokenizer(strExpression))
{
IEnumerable<IToken> paramsTokens = Tokenizer.ParamTokens;
var sst = Tokenizer.EvaluateRPN(keyValuePairs1);
//System.IO.File.WriteAllLines("D:\\1.txt", ss.Select(y => y.ToString()));
System.Diagnostics.Debug.WriteLine("sst=" + sst);
}
2、多次计算
string strExpression2 = "A/0.5+B*C";
Dictionary<string, double[]> keyPairDataList = new Dictionary<string, double[]>();
int sumCount = 5000;
keyPairDataList.Add("A", createRandom(1.17906, 0.04953, sumCount));
keyPairDataList.Add("B", createRandom(1.87478, 0.39739, sumCount));
keyPairDataList.Add("C", createRandom(2.17914, 0.54957, sumCount));
List<Dictionary<string, double>> keyValuePairs = new List<Dictionary<string, double>>();
for (int index = 0; index < sumCount; index++)
{
Dictionary<string, double> aa = new Dictionary<string, double>()
{
{ "A", keyPairDataList["A"][index]},
{ "B", keyPairDataList["B"][index]},
{ "C", keyPairDataList["C"][index]},
};
keyValuePairs.Add(aa);
}
IEnumerable<object> ss = new List<object>();
using (Tokenizer Tokenizer = new Tokenizer(strExpression2))
{
IEnumerable<IToken> paramsTokens = Tokenizer.ParamTokens;
ss = Tokenizer.EvaluateRPN(keyValuePairs);
System.IO.File.WriteAllLines("D:\\1.txt", ss.Select(y => y.ToString()));
}
类图:
抽象类Token实现:
/// <summary>
///
/// </summary>
[Serializable]
public abstract class Token : IToken
{
protected TokenType tokenType = TokenType.ERR;
private string szValue = string.Empty;
/// <summary>
/// 构造函数
/// </summary>
protected Token(string szValue)
{
this.szValue = szValue;
}
/// <summary>
/// 返回类型
/// </summary>
public TokenType Type
{
get { return this.tokenType; }
}
/// <summary>
/// 获取表达式块的值
/// </summary>
public string BlockValue
{
get { return this.szValue; }
}
/// <summary>
/// 比较符
/// </summary>
/// <returns></returns>
public static bool operator ==(Token left, string right)
{
return left.BlockValue == right;
}
/// <summary>
/// 比较符
/// </summary>
/// <returns></returns>
public static bool operator !=(Token left, string right)
{
return left.BlockValue != right;
}
/// <summary>
/// 相等
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public override bool Equals(object obj)
{
if ((obj is BracketsToken) == false)
return false;
if (ReferenceEquals(this, obj))
return true;
if (ReferenceEquals(obj, null))
return false;
return this.szValue == (obj as BracketsToken).szValue;
}
/// <summary>
/// 取得哈希值
/// </summary>
/// <returns></returns>
public override int GetHashCode()
{
return this.szValue.GetHashCode();
}
/// <summary>
/// 输出
/// </summary>
/// <returns></returns>
public override string ToString()
{
return string.Format("{0}:{1}", tokenType.ToString(), szValue);
}
/// <summary>
/// 创建Token实例
/// </summary>
/// <param name="szValue"></param>
/// <returns></returns>
internal static IToken Create(string szValue)
{
if (BracketsToken.Map(szValue))
return new BracketsToken(szValue);
if (ArithmeticToken.Map(szValue))
return new ArithmeticToken(szValue);
if (LogicalToken.Map(szValue))
return new LogicalToken(szValue);
if (TriangleToken.Map(szValue))
return new TriangleToken(szValue);
if (ConstIntegerToken.Map(szValue))
return new ConstIntegerToken(szValue);
if (TimeToken.Map(szValue))
return new TimeToken(szValue);
return new ParameterToken(szValue);
}
}
所有的实现继承Token,主要分为:
1、操作符类:BracketsToken(括号)、ArithmeticToken(算术运算)、LogicalToken(逻辑运算)、TriangleToken(三角运算)
2、操作数类:ConstIntegerToken(常量计算)、ParameterToken(参数计算)
编写2个接口:
1、IOperator 操作符接口,接口方法包含:IOperand Eval(IOperand left, IOperand right);
2、IOperand 操作数接口,接口属性包含:VarName(参数名)、VarValue(参数值)
解析实现:
paramTokens.Clear();
arrFinalExpr.Clear();
Stack stkOp = new Stack();
ArrayList bottomList = new ArrayList();
foreach (Token token in this)
{
string szToken = token.BlockValue.Trim();
if (string.IsNullOrEmpty(szToken))
continue;
if ((token is IOperator) == false)
{
if (token is ParameterToken)
{
arrFinalExpr.Add(token as ParameterToken);
paramTokens.Add(token);
continue;
}
arrFinalExpr.Add((token as IOperand));
continue;
}
if (token == "(")
stkOp.Push(token);
else if (token == ")")
{
Token popToken;
while (((popToken = (Token)stkOp.Pop())) != "(")
{
arrFinalExpr.Add(popToken);
if (stkOp.Count == 0)
throw new Exception("Unmatched braces!");
}
}
else
{
if (stkOp.Count == 0 || (Token)stkOp.Peek() == "(" || IsHigherPrecOperator(token, (Token)stkOp.Peek()))
stkOp.Push(token);
else
{
while (stkOp.Count != 0)
{
if (IsLowerPrecOperator(token, (Token)stkOp.Peek()) || IsEqualPrecOperator(token, (Token)stkOp.Peek()))
{
Token szTop = (Token)stkOp.Peek();
if (szTop == "(")
break;
szTop = (Token)stkOp.Pop();
arrFinalExpr.Add((szTop as IOperator));
}
else
break;
}
stkOp.Push(token);
}
}
}
while (stkOp.Count != 0)
{
Token szTop = (Token)stkOp.Pop();
if (szTop == "(")
throw new Exception("Unmatched braces");
arrFinalExpr.Add((szTop as IOperator));
}
计算实现:
/// <summary>
/// 执行计算
/// </summary>
/// <param name="htValues">参数值</param>
/// <returns></returns>
public object EvaluateRPN(Dictionary<string, double> htValues)
{
Stack stPad = new Stack();
foreach (object var in arrFinalExpr)
{
object calcVar = var;
IOperand op1 = null;
IOperand op2 = null;
IOperator oprtr = null;
if (var is ParameterToken && htValues != null)
(calcVar as IOperand).VarValue = htValues[(calcVar as IOperand).VarName];
if (calcVar is IOperand)
stPad.Push(calcVar);
else if (calcVar is IOperator)
{
op2 = (IOperand)stPad.Pop();
if ((calcVar is TriangleToken) == false && stPad.Count != 0)
op1 = (IOperand)stPad.Pop();
oprtr = (IOperator)calcVar;
IOperand opRes = oprtr.Eval(op1, op2);
stPad.Push(opRes);
}
}
return ((IOperand)stPad.Pop()).VarValue;
}
下载:https://download.csdn.net/download/fuweiping/15931044
NET5.0,VS2019