评估字符串"3*(4 + 2)"产生int 18

sin*_*e j 95 c# string math numeric evaluate

.NET框架是否有一个函数可以计算字符串中包含的数字表达式并返回结果?铁:

string mystring = "3*(2+4)";
int result = EvaluateExpression(mystring);
Console.Writeln(result); // Outputs 18
Run Code Online (Sandbox Code Playgroud)

是否有标准框架功能,您可以用我的EvaluateExpression方法替换?

小智 137

如果要评估字符串表达式,请使用以下代码段.

using System.Data;

DataTable dt = new DataTable();
var v = dt.Compute("3 * (2+4)","");
Run Code Online (Sandbox Code Playgroud)

  • 感觉很脏,使用数据表进行简单的数学计算.NCalc或其他一些数学专用库将是一个更好的主意iMO. (7认同)
  • .NET Core 现在支持 DataTable:https://blogs.msdn.microsoft.com/devfish/2017/05/15/exploring-datatable-and-sqldbadapter-in-asp-net-core-2-0/ (3认同)
  • 这是迄今为止最好、最简单、最快且开销最小的解决方案。如果可以的话我会“+2” (3认同)
  • 出色地!如果你正在接受面试,他们要求你为此编写算法,那么使用这种方法肯定会标志着你的拒绝:) 期待一些算法 (2认同)

Séb*_*SFT 74

使用编译器意味着内存泄漏,因为生成的程序集已加载并且从未释放.它的性能也不如使用真正的表达式解释器.为此,您可以使用Ncalc,这是一个开源框架,仅此目的.如果已包含的变量和自定义函数不够,您还可以定义自己的变量和自定义函数.

例:

Expression e = new Expression("2 + 3 * 5");
Debug.Assert(17 == e.Evaluate());
Run Code Online (Sandbox Code Playgroud)

  • 使用编译器也是一个巨大的安全风险.您打算允许数字表达式,但突然间您暴露了更像PowerShell的东西 (16认同)

Pet*_*pac 49

试试这个:

static double Evaluate(string expression) {
  var loDataTable = new DataTable();
  var loDataColumn = new DataColumn("Eval", typeof (double), expression);
  loDataTable.Columns.Add(loDataColumn);
  loDataTable.Rows.Add(0);
  return (double) (loDataTable.Rows[0]["Eval"]);
}
Run Code Online (Sandbox Code Playgroud)

  • 有人可以解释为什么这有效吗? (11认同)
  • @ChrisTrombley:`DataColumn.Expression`属性支持一种包含基本算术运算符和一些有用函数的小语言.@Petar正在做的是创建一个新的列,其`Expression`属性设置为指定的表达式.之后,当他访问该列的值时,DataTable会计算表达式并计算该值,然后将其返回给调用者.有关支持的运算符和函数的详细信息,请参阅http://msdn.microsoft.com/en-us/library/system.data.datacolumn.expression.aspx. (5认同)

aru*_*rul 42

是的,您可以让C#编译器在运行时对其进行评估.

请参阅:CSharpCorner

  • @sindre有人问过,如果有一个框架函数,那个页面会徘徊,并得到一个关于使用DataTable的Compute方法的有趣答案:http://stackoverflow.com/questions/2859111/c-math-calculator/2859130#2859130 (12认同)

小智 14

您可以查看"XpathNavigator.Evaluate"我已经使用它来处理我的GridView的数学表达式,它对我来说很好.

这是我用于我的程序的代码:

public static double Evaluate(string expression)
{
    return (double)new System.Xml.XPath.XPathDocument
    (new StringReader("<r/>")).CreateNavigator().Evaluate
    (string.Format("number({0})", new
    System.Text.RegularExpressions.Regex(@"([\+\-\*])")
    .Replace(expression, " ${1} ")
    .Replace("/", " div ")
    .Replace("%", " mod ")));
}
Run Code Online (Sandbox Code Playgroud)


mis*_*her 14

static double Evaluate(string expression) { 
  var loDataTable = new DataTable(); 
  var loDataColumn = new DataColumn("Eval", typeof (double), expression); 
  loDataTable.Columns.Add(loDataColumn); 
  loDataTable.Rows.Add(0); 
  return (double) (loDataTable.Rows[0]["Eval"]); 
} 
Run Code Online (Sandbox Code Playgroud)

解释它是如何工作的:

首先,我们在部件中创建一个表var loDataTable = new DataTable();,就像在数据库引擎(例如MS SQL)中一样.

然后,一列,带有一些特定的参数(var loDataColumn = new DataColumn("Eval", typeof (double), expression);).

"Eval"参数是列的名称(ColumnName属性).

typeof (double)是要存储在列中的数据类型,它等于put System.Type.GetType("System.Double");.

expressionEvaluate方法接收的字符串,并存储在Expression列的属性中.这个属性用于一个非常特定的目的(显而易见),即放在列上的每一行都将使用"Expression"填充,并且它实际上接受了wathever可以放入SQL查询中.请参阅http://msdn.microsoft.com/en-us/library/system.data.datacolumn.expression(v=vs.100).aspx以了解可以在Expression属性中放置什么,以及如何评估它.

然后,loDataTable.Columns.Add(loDataColumn);将列添加loDataColumnloDataTable表中.

然后,将一行添加到具有Expression属性的个性化列的表中,通过完成loDataTable.Rows.Add(0);.当我们添加这一行时,表的"Eval"列的单元格loDataTable会自动使用其"Expression"属性进行填充,如果它具有运算符和SQL查询等,则会对其进行评估,然后将其存储到单元格中,因此,这里发生了"魔术",运算符的字符串被评估并存储到单元格中......

最后,只返回存储到第0行"Eval"列的单元格中的值(它是一个索引,从零开始计数),然后转换为double return (double) (loDataTable.Rows[0]["Eval"]);.

这就是全部......完成工作!

这里有一个代码eaiser来理解,它做同样的......它不在一个方法中,它也被解释了.

DataTable MyTable = new DataTable();
DataColumn MyColumn = new DataColumn();
MyColumn.ColumnName = "MyColumn";
MyColumn.Expression = "5+5/5"
MyColumn.DataType = typeof(double);
MyTable.Columns.Add(MyColumn);
DataRow MyRow = MyTable.NewRow();
MyTable.Rows.Add(MyRow);
return (double)(MyTable.Rows[0]["MyColumn"]);
Run Code Online (Sandbox Code Playgroud)

首先,用表创建表 DataTable MyTable = new DataTable();

然后,一列用 DataColumn MyColumn = new DataColumn();

接下来,我们为列添加一个名称.这样我们就可以在它存储到表格时搜索它的内容.完成通过MyColumn.ColumnName = "MyColumn";

然后,表达式,这里我们可以放一个字符串类型的变量,在这种情况下有一个预定义的字符串"5 + 5/5",结果是6.

要存储到列的数据类型 MyColumn.DataType = typeof(double);

将列添加到表中... MyTable.Columns.Add(MyColumn);

将一行插入到表中,该表复制表结构 DataRow MyRow = MyTable.NewRow();

将行添加到表中 MyTable.Rows.Add(MyRow);

并返回单元格的值在0行的列的MyColumnMyTablereturn (double)(MyTable.Rows[0]["MyColumn"]);

完成课程!!!


Taw*_*ani 12

这是一个使用Stacks的简单表达式求值程序

public class MathEvaluator
{
    public static void Run()
    {
        Eval("(1+2)");
        Eval("5*4/2");
        Eval("((3+5)-6)");
    }

    public static void Eval(string input)
    {
        var ans = Evaluate(input);
        Console.WriteLine(input + " = " + ans);
    }

    public static double Evaluate(String input)
    {
        String expr = "(" + input + ")";
        Stack<String> ops = new Stack<String>();
        Stack<Double> vals = new Stack<Double>();

        for (int i = 0; i < expr.Length; i++)
        {
            String s = expr.Substring(i, 1);
            if (s.Equals("(")){}
            else if (s.Equals("+")) ops.Push(s);
            else if (s.Equals("-")) ops.Push(s);
            else if (s.Equals("*")) ops.Push(s);
            else if (s.Equals("/")) ops.Push(s);
            else if (s.Equals("sqrt")) ops.Push(s);
            else if (s.Equals(")"))
            {
                int count = ops.Count;
                while (count > 0)
                {
                    String op = ops.Pop();
                    double v = vals.Pop();
                    if (op.Equals("+")) v = vals.Pop() + v;
                    else if (op.Equals("-")) v = vals.Pop() - v;
                    else if (op.Equals("*")) v = vals.Pop()*v;
                    else if (op.Equals("/")) v = vals.Pop()/v;
                    else if (op.Equals("sqrt")) v = Math.Sqrt(v);
                    vals.Push(v);

                    count--;
                }
            }
            else vals.Push(Double.Parse(s));
        }
        return vals.Pop();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 好吧.但是它并没有遵循算术优先级,就像在bracks中它应该首先计算除法然后乘法然后加法等等. (5认同)

小智 7

这是从右到左的执行,因此需要使用适当的插补来执行表达式

    // 2+(100/5)+10 = 32
    //((2.5+10)/5)+2.5 = 5
    // (2.5+10)/5+2.5 = 1.6666
    public static double Evaluate(String expr)
    {

        Stack<String> stack = new Stack<String>();

        string value = "";
        for (int i = 0; i < expr.Length; i++)
        {
            String s = expr.Substring(i, 1);
            char chr = s.ToCharArray()[0];

            if (!char.IsDigit(chr) && chr != '.' && value != "")
            {
                stack.Push(value);
                value = "";
            }

            if (s.Equals("(")) {

                string innerExp = "";
                i++; //Fetch Next Character
                int bracketCount=0;
                for (; i < expr.Length; i++)
                {
                    s = expr.Substring(i, 1);

                    if (s.Equals("("))
                        bracketCount++;

                    if (s.Equals(")"))
                        if (bracketCount == 0)
                            break;
                        else
                            bracketCount--;


                    innerExp += s;
                }

                stack.Push(Evaluate(innerExp).ToString());

            }
            else if (s.Equals("+")) stack.Push(s);
            else if (s.Equals("-")) stack.Push(s);
            else if (s.Equals("*")) stack.Push(s);
            else if (s.Equals("/")) stack.Push(s);
            else if (s.Equals("sqrt")) stack.Push(s);
            else if (s.Equals(")"))
            {
            }
            else if (char.IsDigit(chr) || chr == '.')
            {
                value += s;

                if (value.Split('.').Length > 2)
                    throw new Exception("Invalid decimal.");

                if (i == (expr.Length - 1))
                    stack.Push(value);

            }
            else
                throw new Exception("Invalid character.");

        }


        double result = 0;
        while (stack.Count >= 3)
        {

            double right = Convert.ToDouble(stack.Pop());
            string op = stack.Pop();
            double left = Convert.ToDouble(stack.Pop());

            if (op == "+") result = left + right;
            else if (op == "+") result = left + right;
            else if (op == "-") result = left - right;
            else if (op == "*") result = left * right;
            else if (op == "/") result = left / right;

            stack.Push(result.ToString());
        }


        return Convert.ToDouble(stack.Pop());
    }
Run Code Online (Sandbox Code Playgroud)


Jon*_*eet 3

您可以相当轻松地通过 CSharpCodeProvider 运行它,并使用合适的绒毛包装它(基本上是类型和方法)。同样,您可以使用 VB 等 - 或 JavaScript,正如另一个答案所建议的那样。目前我不知道框架中还内置了任何其他内容。

我预计 .NET 4.0 及其对动态语言的支持很可能在这方面具有更好的功能。