C# 运算符作为字符串

C# 运算符作为字符串,c#,C#,我需要计算一个数学表达式,它在C#中作为字符串呈现给我。示例noddy,但获取字符串作为表达式的点 我需要求值,然后填充一个int 与其他语言一样,C语言中没有Eval() String myString = "3*4"; 编辑: 我在VS2008上 已尝试Microsoft.JScript其已弃用的方法(但仍符合-警告) 但是,我使用的Microsoft.JScript dll不起作用 公共对象调用成员(字符串 名称、BindingFlags调用EATTR、活页夹 活页夹、对象目标、对象[]

我需要计算一个数学表达式,它在C#中作为字符串呈现给我。示例noddy,但获取字符串作为表达式的点

我需要求值,然后填充一个int

与其他语言一样,C语言中没有Eval()

String myString = "3*4";
编辑:

我在VS2008上

已尝试Microsoft.JScript其已弃用的方法(但仍符合-警告)

但是,我使用的Microsoft.JScript dll不起作用

公共对象调用成员(字符串 名称、BindingFlags调用EATTR、活页夹 活页夹、对象目标、对象[]参数)

抱怨说有一个“失踪”;“去找找看

编辑2

解决方案-是codeDom一个-它的工作,因为没有安全问题-只有我将运行代码。非常感谢您的回复

还有新龙书的链接真是太棒了

编辑3


Matt dataTable.Compute()也可以工作,对于安全意识更强的人来说效果更好。(注意参数检查)

您可以使用jscript解释器。 这里有一篇很棒的文章:

当你说“喜欢其他语言”时,你应该说“喜欢动态语言”

对于python、ruby和许多解释语言等动态语言,Eval()函数是一个自然元素。事实上,实现自己的功能甚至可能非常简单


然而,.Net的核心是一个静态、强类型、编译平台(至少在动态语言运行时获得更多支持之前是这样)。这具有自然的优势,比如代码注入安全性和编译时类型检查,这些都是很难忽略的。但这意味着Eval()函数不是很合适——它希望能够提前编译表达式。在这种平台中,通常有其他更安全的方法来完成相同的任务。

在解释语言中,您可能有机会使用解释器评估字符串。在C#中,您需要一个用于编写字符串的语言(数学表达式语言)的解析器。这是一个非常重要的练习。如果您想这样做,请使用递归下降解析器。《龙之书》的早期章节(编者:设计等,由Aho、Sethi和Ullman编写,1977年第1版或2007年第2版)很好地解释了您需要做什么

另一种方法是在项目中包含一个用perl编写的组件,该组件现在应该可以用于.NET,并使用perl进行计算。

可以,或者如果表达式很简单,您也可以编写自己的解析器(注意,它会很快变得复杂)

我很确定C#中没有直接的“Eval(string)”方法,因为它不会被解释


请记住,尽管代码解释需要代码注入,但要格外小心:)

计算表达式时是否需要访问其他变量的值?

在我看来,您有两种选择-使用表达式计算器或构造、编译 并动态运行C#代码

我会使用表达式计算器库,因为您不必担心任何安全问题。也就是说,您可能无法在中等信任环境(如大多数共享托管服务器)中使用代码生成

以下是生成代码以计算表达式的示例:

通过谷歌搜索,我发现可以使用CodeDom动态创建和编译代码。(见a)


我个人认为这种方法不是一个很好的主意,因为用户可以输入他想要的任何代码,但这可能是一个需要探索的领域(例如,只验证输入,只允许数字和简单的数学运算)。

请查看

所有其他答案都可能是多余的

如果你所需要的只是简单的算术,那么就这样做吧

        DataTable dummy = new DataTable();
        Console.WriteLine(dummy.Compute("15 / 3",string.Empty));

编辑:更多信息。查看MSDN文档,了解
System.Data.DataColumn
类的
表达式
属性。“表达式语法”中的内容概述了除了算术运算符之外还可以使用的命令列表。(例如IIF、LEN等)。谢谢大家投票支持我第一次发布的答案

其他一些建议:

  • Mono 2.0(今天发布)有一个评估方法
  • 您可以轻松地在boo中编写一个特定于域的小程序
  • 您可以创建一个老式的递归下降EBNF解析器

    • 几周前,我在C#做了一次个人练习

      这是一段相当多的代码,有些地方的注释很差。但是它确实在很多测试用例中工作

      享受吧

      using System;
      using System.Collections.Generic;
      using System.Text.RegularExpressions;
      
      namespace StackOverflow
      {
          class Start
          {
              public static void Main(string[] args)
              {
                  Evaluator ev;
                  string variableValue, eq;
              Console.Write("Enter equation:  ");
              eq = Console.ReadLine();
      
              while (eq != "quit")
              {
                  ev = new Evaluator(eq);
                  foreach (Variable v in ev.Variables)
                  {
                      Console.Write(v.Name + " = ");
                      variableValue = Console.ReadLine();
                      ev.SetVariable(v.Name, Convert.ToDecimal(variableValue));
                  }
      
                  Console.WriteLine(ev.Evaluate());
      
                  Console.Write("Enter equation:  ");
                  eq = Console.ReadLine();
              }
          }
      }
      
      class EvalNode
      {
          public virtual decimal Evaluate()
          {
              return decimal.Zero;
          }
      }
      
      class ValueNode : EvalNode
      {
          decimal value;
      
          public ValueNode(decimal v)
          {
              value = v;
          }
      
          public override decimal Evaluate()
          {
              return value;
          }
      
          public override string ToString()
          {
              return value.ToString();
          }
      }
      
      class FunctionNode : EvalNode
      {
          EvalNode lhs = new ValueNode(decimal.Zero);
          EvalNode rhs = new ValueNode(decimal.Zero);
          string op = "+";
      
          public string Op
          {
              get { return op; }
              set
              {
                  op = value;
              }
          }
      
          internal EvalNode Rhs
          {
              get { return rhs; }
              set
              {
                  rhs = value;
              }
          }
      
          internal EvalNode Lhs
          {
              get { return lhs; }
              set
              {
                  lhs = value;
              }
          }
      
          public override decimal Evaluate()
          {
              decimal result = decimal.Zero;
      
              switch (op)
              {
                  case "+":
                      result = lhs.Evaluate() + rhs.Evaluate();
                      break;
      
                  case "-":
                      result = lhs.Evaluate() - rhs.Evaluate();
                      break;
      
                  case "*":
                      result = lhs.Evaluate() * rhs.Evaluate();
                      break;
      
                  case "/":
                      result = lhs.Evaluate() / rhs.Evaluate();
                      break;
      
                  case "%":
                      result = lhs.Evaluate() % rhs.Evaluate();
                      break;
      
                  case "^":
                      double x = Convert.ToDouble(lhs.Evaluate());
                      double y = Convert.ToDouble(rhs.Evaluate());
      
                      result = Convert.ToDecimal(Math.Pow(x, y));
                      break;
      
                  case "!":
                      result = Factorial(lhs.Evaluate());
                      break;
              }
      
              return result;
          }
      
          private decimal Factorial(decimal factor)
          {
              if (factor < 1)
                  return 1;
      
              return factor * Factorial(factor - 1);
          }
      
          public override string ToString()
          {
              return "(" + lhs.ToString() + " " + op + " " + rhs.ToString() + ")";
          }
      }
      
      public class Evaluator
      {
          string equation = "";
          Dictionary<string, Variable> variables = new Dictionary<string, Variable>();
      
          public string Equation
          {
              get { return equation; }
              set { equation = value; }
          }
      
          public Variable[] Variables
          {
              get { return new List<Variable>(variables.Values).ToArray(); }
          }
      
          public void SetVariable(string name, decimal value)
          {
              if (variables.ContainsKey(name))
              {
                  Variable x = variables[name];
                  x.Value = value;
                  variables[name] = x;
              }
          }
      
          public Evaluator(string equation)
          {
              this.equation = equation;
              SetVariables();
          }
      
          public decimal Evaluate()
          {
              return Evaluate(equation, new List<Variable>(variables.Values));
          }
      
          public decimal Evaluate(string text)
          {
              decimal result = decimal.Zero;
              equation = text;
              EvalNode parsed;
      
              equation = equation.Replace(" ", "");
      
              parsed = Parse(equation, "qx");
      
              if (parsed != null)
                  result = parsed.Evaluate();
      
              return result;
          }
      
          public decimal Evaluate(string text, List<Variable> variables)
          {
              foreach (Variable v in variables)
              {
                  text = text.Replace(v.Name, v.Value.ToString());
              }
      
              return Evaluate(text);
          }
      
          private static bool EquationHasVariables(string equation)
          {
              Regex letters = new Regex(@"[A-Za-z]");
      
              return letters.IsMatch(equation);
          }
      
          private void SetVariables()
          {
              Regex letters = new Regex(@"([A-Za-z]+)");
              Variable v;
      
              foreach (Match m in letters.Matches(equation, 0))
              {
                  v = new Variable(m.Groups[1].Value, decimal.Zero);
      
                  if (!variables.ContainsKey(v.Name))
                  {
                      variables.Add(v.Name, v);
                  }
              }
          }
      
          #region Parse V2
      
          private Dictionary<string, string> parenthesesText = new Dictionary<string, string>();
      
          /*
           * 1.  All the text in first-level parentheses is replaced with replaceText plus an index value.
           *      (All nested parentheses are parsed in recursive calls)
           * 2.  The simple function is parsed given the order of operations (reverse priority to 
           *      keep the order of operations correct when evaluating).
           *      a.  Addition (+), subtraction (-)                   -> left to right
           *      b.  Multiplication (*), division (/), modulo (%)    -> left to right
           *      c.  Exponents (^)                                   -> right to left
           *      d.  Factorials (!)                                  -> left to right
           *      e.  No op (number, replaced parentheses) 
           * 3.  When an op is found, a two recursive calls are generated -- parsing the LHS and 
           *      parsing the RHS.
           * 4.  An EvalNode representing the root node of the evaluations tree is returned.
           * 
           * Ex.  3 + 5                   (3 + 5) * 8
           *           +                          *
           *          / \                        / \
           *         3   5                      +   8
           *                                   / \ 
           *      3 + 5 * 8                   3   5
           *            +
           *           / \
           *          3   *
           *             / \
           *            5   8
           */
      
          /// <summary>
          /// Parses the expression and returns the root node of a tree.
          /// </summary>
          /// <param name="eq">Equation to be parsed</param>
          /// <param name="replaceText">Text base that replaces text in parentheses</param>
          /// <returns></returns>
          private EvalNode Parse(string eq, string replaceText)
          {
              int randomKeyIndex = 0;
      
              eq = eq.Replace(" ", "");
              if (eq.Length == 0)
              {
                  return new ValueNode(decimal.Zero);
              }
      
              int leftParentIndex = -1;
              int rightParentIndex = -1;
              SetIndexes(eq, ref leftParentIndex, ref rightParentIndex);
      
              //remove extraneous outer parentheses
              while (leftParentIndex == 0 && rightParentIndex == eq.Length - 1)
              {
                  eq = eq.Substring(1, eq.Length - 2);
                  SetIndexes(eq, ref leftParentIndex, ref rightParentIndex);
              }
      
              //Pull out all expressions in parentheses
              replaceText = GetNextReplaceText(replaceText, randomKeyIndex);
      
              while (leftParentIndex != -1 && rightParentIndex != -1)
              {
                  //replace the string with a random set of characters, stored extracted text in dictionary keyed on the random set of chars
      
                  string p = eq.Substring(leftParentIndex, rightParentIndex - leftParentIndex + 1);
                  eq = eq.Replace(p, replaceText);
                  parenthesesText.Add(replaceText, p);
      
                  leftParentIndex = 0;
                  rightParentIndex = 0;
      
                  replaceText = replaceText.Remove(replaceText.LastIndexOf(randomKeyIndex.ToString()));
                  randomKeyIndex++;
                  replaceText = GetNextReplaceText(replaceText, randomKeyIndex);
      
                  SetIndexes(eq, ref leftParentIndex, ref rightParentIndex);
              }
      
              /*
               * Be sure to implement these operators in the function node class
               */
              char[] ops_order0 = new char[2] { '+', '-' };
              char[] ops_order1 = new char[3] { '*', '/', '%' };
              char[] ops_order2 = new char[1] { '^' };
              char[] ops_order3 = new char[1] { '!' };
      
              /*
               * In order to evaluate nodes LTR, the right-most node must be the root node
               * of the tree, which is why we find the last index of LTR ops.  The reverse 
               * is the case for RTL ops.
               */
      
              int order0Index = eq.LastIndexOfAny(ops_order0);
      
              if (order0Index > -1)
              {
                  return CreateFunctionNode(eq, order0Index, replaceText + "0");
              }
      
              int order1Index = eq.LastIndexOfAny(ops_order1);
      
              if (order1Index > -1)
              {
                  return CreateFunctionNode(eq, order1Index, replaceText + "0");
              }
      
              int order2Index = eq.IndexOfAny(ops_order2);
      
              if (order2Index > -1)
              {
                  return CreateFunctionNode(eq, order2Index, replaceText + "0");
              }
      
              int order3Index = eq.LastIndexOfAny(ops_order3);
      
              if (order3Index > -1)
              {
                  return CreateFunctionNode(eq, order3Index, replaceText + "0");
              }
      
              //no operators...
              eq = eq.Replace("(", "");
              eq = eq.Replace(")", "");
      
              if (char.IsLetter(eq[0]))
              {
                  return Parse(parenthesesText[eq], replaceText + "0");
              }
      
              return new ValueNode(decimal.Parse(eq));
          }
      
          private string GetNextReplaceText(string replaceText, int randomKeyIndex)
          {
              while (parenthesesText.ContainsKey(replaceText))
              {
                  replaceText = replaceText + randomKeyIndex.ToString();
              }
              return replaceText;
          }
      
          private EvalNode CreateFunctionNode(string eq, int index, string randomKey)
          {
              FunctionNode func = new FunctionNode();
              func.Op = eq[index].ToString();
              func.Lhs = Parse(eq.Substring(0, index), randomKey);
              func.Rhs = Parse(eq.Substring(index + 1), randomKey);
      
              return func;
          }
      
          #endregion
      
          /// <summary>
          /// Find the first set of parentheses
          /// </summary>
          /// <param name="eq"></param>
          /// <param name="leftParentIndex"></param>
          /// <param name="rightParentIndex"></param>
          private static void SetIndexes(string eq, ref int leftParentIndex, ref int rightParentIndex)
          {
              leftParentIndex = eq.IndexOf('(');
              rightParentIndex = eq.IndexOf(')');
              int tempIndex = eq.IndexOf('(', leftParentIndex + 1);
      
              while (tempIndex != -1 && tempIndex < rightParentIndex)
              {
                  rightParentIndex = eq.IndexOf(')', rightParentIndex + 1);
                  tempIndex = eq.IndexOf('(', tempIndex + 1);
              }
          }
      }
      
      public struct Variable
      {
          public string Name;
          public decimal Value;
      
          public Variable(string n, decimal v)
          {
              Name = n;
              Value = v;
              }
          }
      }
      
      使用系统;
      使用System.Collections.Generic;
      使用System.Text.RegularExpressions;
      命名空间堆栈溢出
      {
      开课
      {
      公共静态void Main(字符串[]args)
      {
      评价者ev;
      字符串变量值,eq;
      控制台。写入(“输入公式:”);
      eq=Console.ReadLine();
      while(eq!=“退出”)
      {
      ev=新的评估者(eq);
      foreach(ev.变量中的变量v)
      {
      控制台。写入(v.Name+“=”);
      variableValue=Console.ReadLine();
      ev.SetVariable(v.Name,Convert.ToDecimal(variableValue));
      }
      Console.WriteLine(ev.Evaluate());
      控制台。写入(“输入公式:”);
      eq=Console.ReadLine();
      }
      }
      }
      类EvalNode
      {
      公共虚拟十进制求值()
      {
      返回小数点零;
      }
      }
      类ValueNode:EvalNode
      {
      十进制值;
      公共价值节点(十进制v)
      {
      值=v;
      }
      公共重写十进制求值()
      {
      返回值;
      }
      公共重写字符串ToString()
      {
      返回值.ToString();
      }
      }
      类函数节点:EvalNode
      {
      EvalNode lhs=新的ValueNode(十进制零);
      EvalNode rhs=新的ValueNode(十进制零);
      字符串op=“+”;
      公共字符串操作
      {
      G