有没有一种简单的方法来解析代表数学表达式的字符串(例如(x+(2*x)/(1-x))并为x提供一个值并得到结果?
我看了几个在线示例使用VSAEngine,但是我收到了一个警告,说明此程序集已被弃用,请勿再使用。
如果有任何区别的话,我正在使用.NET 4.0。
我建议谨慎选择现有的通用表达式求值器而不是专为数学设计的求值器。原因在于,表达式求值器不仅限于数学。聪明的人可以使用它来创建框架中任何类型的实例,并调用类型上的任何方法,这将允许他做一些绝对不受欢迎的事情。例如:new System.Net.WebClient().DownloadFile("illegalchildpornurl", "C:\openme.gif")
在大多数表达式求值器中都可以正常计算,而且会像它听起来的那样执行(同时使您成为重罪犯)。
这并不意味着不要寻找已经编写好的代码;它只是意味着要小心。您需要的是一个只进行数学计算的求值器。而大多数现有的求值器并没有那么挑剔。
我最近使用了一个叫做mXparser的数学解析库。它提供了很多灵活性,例如变量、函数、常量、运算符。以下是一些使用示例:
示例1 - 简单公式
Expression e = new Expression("1 + pi");
double v = e.calculate();
例子2 - 含有变量、函数等的公式。
Argument x = new Argument("x = 2");
Constant a = new Constant("a = sin(10)");
Function f = new Function("f(t) = t^2");
Expression e = new Expression("2*x + a - f(10)", x, a, f);
double v = e.calculate();
https://mxparser.codeplex.com/
最近发现 - 您可以通过由mXparser提供支持的Scalar Calculator app尝试语法(并查看用例)。我建议您看一下Jace (https://github.com/pieterderycke/Jace)。Jace是一个高性能的数学解析器和计算引擎,支持所有.NET版本(.NET 4.x、Windows Phone、Windows Store等)。Jace也可以通过NuGet获取:https://www.nuget.org/packages/Jace
以下是一种实现方式,这段代码使用Java编写。请注意,它目前还不能处理负数,但您可以添加该功能。
public class ExpressionParser {
public double eval(String exp, Map<String, Double> vars){
int bracketCounter = 0;
int operatorIndex = -1;
for(int i=0; i<exp.length(); i++){
char c = exp.charAt(i);
if(c == '(') bracketCounter++;
else if(c == ')') bracketCounter--;
else if((c == '+' || c == '-') && bracketCounter == 0){
operatorIndex = i;
break;
}
else if((c == '*' || c == '/') && bracketCounter == 0 && operatorIndex < 0){
operatorIndex = i;
}
}
if(operatorIndex < 0){
exp = exp.trim();
if(exp.charAt(0) == '(' && exp.charAt(exp.length()-1) == ')')
return eval(exp.substring(1, exp.length()-1), vars);
else if(vars.containsKey(exp))
return vars.get(exp);
else
return Double.parseDouble(exp);
}
else{
switch(exp.charAt(operatorIndex)){
case '+':
return eval(exp.substring(0, operatorIndex), vars) + eval(exp.substring(operatorIndex+1), vars);
case '-':
return eval(exp.substring(0, operatorIndex), vars) - eval(exp.substring(operatorIndex+1), vars);
case '*':
return eval(exp.substring(0, operatorIndex), vars) * eval(exp.substring(operatorIndex+1), vars);
case '/':
return eval(exp.substring(0, operatorIndex), vars) / eval(exp.substring(operatorIndex+1), vars);
}
}
return 0;
}
您需要导入java.util.Map。
以下是我使用此代码的方法:
ExpressionParser p = new ExpressionParser();
Map vars = new HashMap<String, Double>();
vars.put("x", 2.50);
System.out.println(p.eval(" 5 + 6 * x - 1", vars));
在这个帖子中,我回答了(使用变量、用户定义函数和自定义运算符的最佳免费C#数学解析器),你可以使用Mathos Parser,你只需将其简单地粘贴到源代码中即可。
Mathos.Parser.MathParser parser = new Mathos.Parser.MathParser();
string expr = "(x+(2*x)/(1-x))"; // the expression
decimal result = 0; // the storage of the result
parser.LocalVariables.Add("x", 41); // 41 is the value of x
result = parser.Parse(expr); // parsing
Console.WriteLine(result); // 38.95
你可能想要考虑的另一个选项是Spring.NET框架的表达式求值功能。它不仅可以处理数学运算,还可以做很多其他事情。
然而,如果你不需要其余的功能,整个Spring.NET框架可能有点过度。
我建议您使用MEEL。
// parse string to IExpression (symbolic type)
IExpression expression = BaseExpression.Parse("(x+(2*x)/(1-x))");
// create your own collection for attributes
var attributes = new MathAttributeCollection();
// create local variable named "x" with value 5
var attributeX = new ScalarAttrInt("x") {Value = new ScalarConstInt(5)};
attributes.Add(attributeX);
// execute math expression where x=5
var result = expression.Execute(attributes);
MessageBox.Show(result.GetText());
// result: 2.5