代码之家  ›  专栏  ›  技术社区  ›  sindre j

计算字符串“3*(4+2)”yield int 18[重复]

  •  90
  • sindre j  · 技术社区  · 16 年前

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

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

    是否有标准框架函数可以替换我的 EvaluateExpression 方法与?

    14 回复  |  直到 7 年前
        1
  •  39
  •   arul    16 年前

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

    见: CSharpCorner

        2
  •  123
  •   James Allardice    13 年前

    如果要计算字符串表达式,请使用下面的代码段。

    using System.Data;
    
    DataTable dt = new DataTable();
    var v = dt.Compute("3 * (2+4)","");
    
        3
  •  70
  •   Sébastien Ros - MSFT    15 年前

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

    例子:

    Expression e = new Expression("2 + 3 * 5");
    Debug.Assert(17 == e.Evaluate());
    
        4
  •  48
  •   pero    15 年前

    试试这个:

    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"]);
    }
    
        5
  •  14
  •   Olav Botterli    15 年前

    你可以看看“xpathnavigator.evaluate”,我用它来处理我的网格视图的数学表达式,它对我来说很好。

    以下是我在程序中使用的代码:

    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 ")));
    }
    
        6
  •  11
  •   Tawani    9 年前

    这是一个使用堆栈的简单表达式计算器

    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();
        }
    }
    
        7
  •  11
  •   mishamosher    7 年前
    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"]); 
    } 
    

    解释其工作原理:

    首先,我们做一张桌子 var loDataTable = new DataTable(); 就像在数据库引擎中一样(例如MS SQL)。

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

    这个 "Eval" 参数是列的名称(column name属性)。

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

    expression 是指 Evaluate 方法接收并存储在属性中 Expression 列中的这个属性是为了一个真正特定的目的(明显的),即放在列上的每一行都将被“表达式”填满,它实际上接受wathever可以放在SQL查询中。参照 http://msdn.microsoft.com/en-us/library/system.data.datacolumn.expression(v=vs.100).aspx 了解表达式属性中可以放入什么,以及如何对其进行计算。

    然后, loDataTable.Columns.Add(loDataColumn); 添加列 loDataColumn loDataTable 表。

    然后,将一行添加到具有表达式属性的个性化列的表中,通过 loDataTable.Rows.Add(0); . 当我们添加此行时,表的“eval”列的单元格 可浮动的 自动用它的“expression”属性填充,并且,如果它有操作符和SQL查询等,它将被计算并存储到单元格中,因此,这里出现了“magic”,带有操作符的字符串将被计算并存储到单元格中…

    最后,只需返回存储在第0行“eval”列的单元格中的值(它是一个索引,从零开始计数),并使用 return (double) (loDataTable.Rows[0]["Eval"]); .

    就这些……工作完成了!

    这里有一个需要理解的代码,它的作用是一样的…它不在方法中,也有解释。

    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"]);
    

    首先,使用 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行中单元格的值 MyColumn 桌子的 MyTable 具有 return (double)(MyTable.Rows[0]["MyColumn"]);

    一课!!!!

        8
  •  4
  •   Rajesh Jinaga    14 年前

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

        // 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());
        }
    
        9
  •  3
  •   Jon Skeet    16 年前

    您可以非常容易地通过CSharpCodeProvider运行它,并使用合适的fluff包装它(基本上是一个类型和一个方法)。同样,你也可以通过vb等——或者javascript,正如另一个答案所建议的那样。目前我不知道框架中还内置了其他任何东西。

    我希望支持动态语言的.NET 4.0在这方面可能有更好的功能。

        10
  •  3
  •   Beardo    16 年前

    我最近需要为一个项目做这个,结果我用了 IronPython 做这件事。您可以声明引擎的一个实例,然后传递任何有效的python表达式并获得结果。如果你只是做简单的数学表达式,那就足够了。我的代码最终看起来类似于:

    IronPython.Hosting.PythonEngine pythonEngine = new IronPython.Hosting.PythonEngine();
    string expression = "3*(2+4)";
    double result = pythonEngine.EvaluateAs<double>(expression);
    

    您可能不想为每个表达式创建引擎。您还需要一个对ironpython.dll的引用

        11
  •  3
  •   Fat-Wednesday    14 年前

    编辑: 意识到我真的应该把加减法分开来,让它更符合菩萨的要求。

    非常感谢Rajesh Jinaga基于堆栈的方法。我发现它对我的需要非常有用。下面的代码是对rajesh方法的一个细微修改,它先处理除法,然后进行乘法,最后进行加法和减法运算。它还允许在表达式中使用布尔值,其中true被视为1,false 0。允许在表达式中使用布尔逻辑。

    public static double Evaluate(string expr)
        {
            expr = expr.ToLower();
            expr = expr.Replace(" ", "");
            expr = expr.Replace("true", "1");
            expr = expr.Replace("false", "0");
    
            Stack<String> stack = new Stack<String>();
    
            string value = "";
            for (int i = 0; i < expr.Length; i++)
            {
                String s = expr.Substring(i, 1);
                // pick up any doublelogical operators first.
                if (i < expr.Length - 1)
                {
                    String op = expr.Substring(i, 2);
                    if (op == "<=" || op == ">=" || op == "==")
                    {
                        stack.Push(value);
                        value = "";
                        stack.Push(op);
                        i++;
                        continue;
                    }
                }
    
                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;
                            bracketCount--;
                        }
                        innerExp += s;
                    }
                    stack.Push(Evaluate(innerExp).ToString());
                }
                else if (s.Equals("+") ||
                         s.Equals("-") ||
                         s.Equals("*") ||
                         s.Equals("/") ||
                         s.Equals("<") ||
                         s.Equals(">"))
                {
                    stack.Push(s);
                }
                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;
            List<String> list = stack.ToList<String>();
            for (int i = list.Count - 2; i >= 0; i--)
            {
                if (list[i] == "/")
                {
                    list[i] = (Convert.ToDouble(list[i - 1]) / Convert.ToDouble(list[i + 1])).ToString();
                    list.RemoveAt(i + 1);
                    list.RemoveAt(i - 1);
                    i -= 2;
                }
            }
    
            for (int i = list.Count - 2; i >= 0; i--)
            {
                if (list[i] == "*")
                {
                    list[i] = (Convert.ToDouble(list[i - 1]) * Convert.ToDouble(list[i + 1])).ToString();
                    list.RemoveAt(i + 1);
                    list.RemoveAt(i - 1);
                    i -= 2;
                }
            }
            for (int i = list.Count - 2; i >= 0; i--)
            {
                if (list[i] == "+")
                {
                    list[i] = (Convert.ToDouble(list[i - 1]) + Convert.ToDouble(list[i + 1])).ToString();
                    list.RemoveAt(i + 1);
                    list.RemoveAt(i - 1);
                    i -= 2;
                }
            }
            for (int i = list.Count - 2; i >= 0; i--)
            {
                if (list[i] == "-")
                {
                    list[i] = (Convert.ToDouble(list[i - 1]) - Convert.ToDouble(list[i + 1])).ToString();
                    list.RemoveAt(i + 1);
                    list.RemoveAt(i - 1);
                    i -= 2;
                }
            }
            stack.Clear();
            for (int i = 0; i < list.Count; i++)
            {
                stack.Push(list[i]);
            }
            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) ? 1 : 0;
                else if (op == ">") result = (left > right) ? 1 : 0;
                else if (op == "<=") result = (left <= right) ? 1 : 0;
                else if (op == ">=") result = (left >= right) ? 1 : 0;
                else if (op == "==") result = (left == right) ? 1 : 0;
    
                stack.Push(result.ToString());
            }
            return Convert.ToDouble(stack.Pop());
        }
    

    我知道有一种更清洁的方法可以做到这一点,我想我只是分享一下第一眼,以防有人发现它有用。

        12
  •  2
  •   nmc Dihui Bao    12 年前

    多亏了拉梅什。我用他的一个简单代码版本从数据库中拉出一个字符串,然后用它在我的代码中做布尔操作。

    X是一个像1500或2100之类的数字。

    函数将是存储的评估,如x>1400和x<1600

    function = relation[0].Replace("and","&&").Replace("x",x);
    
    DataTable f_dt = new DataTable();
    var f_var = f_dt.Compute(function,"");
    
    if (bool.Parse(f_var.ToString()) { do stuff  }
    
        13
  •  1
  •   Tamas Czinege    16 年前

    没有。您需要使用一些外部库,或者编写自己的解析器。如果您有时间这样做,我建议您编写自己的解析器,因为它是一个非常有趣的项目。否则你需要使用 bcParser .

        14
  •  -1
  •   Lster    16 年前

    简短回答:我不这么认为。据我所知,C.NET是编译(到字节码)的,不能在运行时计算字符串。然而,jscript.net可以;但是我仍然建议您自己编写一个解析器和基于堆栈的评估器。