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