当前位置:  开发笔记 > 编程语言 > 正文

运算符为字符串

如何解决《运算符为字符串》经验,为你挑选了3个好方法。

我需要评估一个在C#中作为字符串呈现给我的数学表达式.示例noddy但是得到了字符串作为表达式的点.

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

C#中没有Eval(),就像其他langugaes一样......

String myString = "3*4";

编辑:

我在VS2008上

试过Microsoft.JScript.=已弃用的方法(但仍然符合 - 警告)

但是,我已经使用的Microsoft.JScript DLL工作了

public object InvokeMember(string name,BindingFlags invokeAttr,Binder binder,object target,object [] args);

抱怨缺少";" 去搞清楚...

编辑2

解决方案 - 是codeDom之一 - 因为没有安全问题,所以它工作 - 只有我才能运行代码.非常感谢回复......

和新龙书的链接真棒

编辑3

Matt dataTable.Compute()也有效 - 对于安全意识更好.(注明参数检查)



1> Matt Crouch..:

所有其他答案都可能过度杀伤.

如果您只需要简单的算术运算,请执行此操作.

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

编辑:更多信息.查看MSDN文档以Expression获取System.Data.DataColumn该类的属性."表达式语法"中的内容概述了除算术运算符外还可以使用的命令列表.(例如,IIF,LEN等).谢谢大家投票给我的第一个答案!



2> Tsvetomir Ts..:

我看到它的方式,你有两个选择 - 使用表达式求值程序或构建,编译和运行C#代码.

我会选择表达式评估程序库,因为您不必担心任何安全问题.也就是说,您可能无法在中型信任环境中使用代码生成,例如大多数共享托管服务器.

以下是生成用于计算表达式的代码的示例:http: //www.vbforums.com/showthread.php?t = 397264



3> Austin Salon..:

几个星期前,我在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 variables = new Dictionary();

    public string Equation
    {
        get { return equation; }
        set { equation = value; }
    }

    public Variable[] Variables
    {
        get { return new List(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(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 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 parenthesesText = new Dictionary();

    /*
     * 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
     */

    /// 
    /// Parses the expression and returns the root node of a tree.
    /// 
    /// Equation to be parsed
    /// Text base that replaces text in parentheses
    /// 
    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

    /// 
    /// Find the first set of parentheses
    /// 
    /// 
    /// 
    /// 
    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;
        }
    }
}

推荐阅读
落单鸟人
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有