2

Possible Duplicate:
Is there a string math evaluator in .NET?

Can C# parse mathematical expressions such as y=3*x + 3 into string? If so, ho? I appreciate your help.

Community
  • 1
  • 1
George Tyler
  • 381
  • 2
  • 4
  • 4
  • You'll have to give more information than that: what do you want to do with the expression? Do you want to calculate the value of 'y' given a certain 'x'? Do you want to plot a graph of the equation? Something else? – Dean Harding May 18 '10 at 00:35
  • "Can language X do Y" questions are incredibly silly, since the answer is almost always (at least) "it can if you write the code to do it!" – hobbs May 18 '10 at 00:40

4 Answers4

5

Here's a bit of code I wrote a while ago to parse infix (operator operand operator) equations. There are some small classes and helper functions missing, but it should be fairly easy to implement them. If you need them or any help with it, let me know and I can upload them somewhere.

It's a basic implementation of Dijkstra's Shunting-yard algorithm

public Operand ExpressionTree
{
    get;
    private set;
}

private Stack<Operands.Operand> stack = new Stack<InfixParser.Operands.Operand>();
private Queue<Operands.Operand> outputQueue = new Queue<InfixParser.Operands.Operand>();

private void ParseFormulaString()
{
    //Dijkstra's Shunting Yard Algorithm
    Regex re = new Regex(@"([\+\-\*\(\)\^\/\ ])");
    List<String> tokenList = re.Split(formulaString).Select(t => t.Trim()).Where(t => t != "").ToList();

    for (int tokenNumber = 0; tokenNumber < tokenList.Count(); ++tokenNumber)
    {
        String token = tokenList[tokenNumber];
        TokenClass tokenClass = GetTokenClass(token);

        switch (tokenClass)
        {
            case TokenClass.Value:
                outputQueue.Enqueue(new Value(token));
                break;
            case TokenClass.Function:
                stack.Push(new Function(token, 1));
                break;
            case TokenClass.Operator:
                if (token == "-" && (stack.Count == 0 || tokenList[tokenNumber - 1] == "("))
                {
                    //Push unary operator 'Negative' to stack
                    stack.Push(new Negative());
                    break;
                }
                if (stack.Count > 0)
                {
                    String stackTopToken = stack.Peek().Token;
                    if (GetTokenClass(stackTopToken) == TokenClass.Operator)
                    {
                        Associativity tokenAssociativity = GetOperatorAssociativity(token);
                        int tokenPrecedence = GetOperatorPrecedence(token);
                        int stackTopPrecedence = GetOperatorPrecedence(stackTopToken);

                        if (tokenAssociativity == Associativity.Left && tokenPrecedence <= stackTopPrecedence ||
                            tokenAssociativity == Associativity.Right && tokenPrecedence < stackTopPrecedence)
                        {
                            outputQueue.Enqueue(stack.Pop());
                        }
                    }
                }
                stack.Push(new BinaryOperator(token, Operator.OperatorNotation.Infix));
                break;
            case TokenClass.LeftParen:
                stack.Push(new LeftParenthesis());
                break;
            case TokenClass.RightParen:
                while (!(stack.Peek() is LeftParenthesis))
                {
                    outputQueue.Enqueue(stack.Pop());
                }
                stack.Pop();

                if (stack.Count > 0 && stack.Peek() is Function)
                {
                    outputQueue.Enqueue(stack.Pop());
                }
                break;
        }

        if (tokenClass == TokenClass.Value || tokenClass == TokenClass.RightParen)
        {
            if (tokenNumber < tokenList.Count() - 1)
            {
                String nextToken = tokenList[tokenNumber + 1];
                TokenClass nextTokenClass = GetTokenClass(nextToken);
                if (nextTokenClass != TokenClass.Operator && nextTokenClass != TokenClass.RightParen)
                {
                    tokenList.Insert(tokenNumber + 1, "*");
                }
            }
        }
    }

    while (stack.Count > 0)
    {
        Operand operand = stack.Pop();
        if (operand is LeftParenthesis || operand is RightParenthesis)
        {
            throw new ArgumentException("Mismatched parentheses");
        }

        outputQueue.Enqueue(operand);
    }

    String foo = String.Join(",", outputQueue.Select(t => t.Token).ToArray());
    String bar = String.Join("", tokenList.ToArray());

    Stack<Operand> expressionStack = new Stack<Operand>();
    while (outputQueue.Count > 0)
    {
        Operand operand = outputQueue.Dequeue();

        if (operand is Value)
        {
            expressionStack.Push(operand);
        }
        else
        {
            if (operand is BinaryOperator)
            {
                BinaryOperator op = (BinaryOperator)operand;
                Operand rightOperand = expressionStack.Pop();
                Operand leftOperand = expressionStack.Pop();
                op.LeftOperand = leftOperand;
                op.RightOperand = rightOperand;
            }
            else if (operand is UnaryOperator)
            {
                ((UnaryOperator)operand).Operand = expressionStack.Pop();
            }
            else if (operand is Function)
            {
                Function function = (Function)operand;
                for (int argNum = 0; argNum < function.NumArguments; ++argNum)
                {
                    function.Arguments.Add(expressionStack.Pop());
                }
            }

            expressionStack.Push(operand);
        }
    }

    if (expressionStack.Count != 1)
    {
        throw new ArgumentException("Invalid formula");
    }

    ExpressionTree = expressionStack.Pop();
}

private TokenClass GetTokenClass(String token)
{
    double tempValue;
    if (double.TryParse(token, out tempValue) ||
        token.Equals("R", StringComparison.CurrentCultureIgnoreCase) ||
        token.Equals("S", StringComparison.CurrentCultureIgnoreCase))
    {
        return TokenClass.Value;
    }
    else if (token.Equals("sqrt", StringComparison.CurrentCultureIgnoreCase))
    {
        return TokenClass.Function;
    }
    else if (token == "(")
    {
        return TokenClass.LeftParen;
    }
    else if (token == ")")
    {
        return TokenClass.RightParen;
    }
    else if (binaryInfixOperators.Contains(token))
    {
        return TokenClass.Operator;
    }
    else
    {
        throw new ArgumentException("Invalid token");
    }
}

private Associativity GetOperatorAssociativity(String token)
{
    if (token == "^")
        return Associativity.Right;
    else
        return Associativity.Left;
}

private int GetOperatorPrecedence(String token)
{
    if (token == "+" || token == "-")
    {
        return 1;
    }
    else if (token == "*" || token == "/")
    {
        return 2;
    }
    else if (token == "^")
    {
        return 3;
    }
    else
    {
        throw new ArgumentException("Invalid token");
    }
}
TheEvilPenguin
  • 5,634
  • 1
  • 26
  • 47
  • Could you please upload the complete program some where ? Thanks in Advance – Ananth Mar 07 '15 at 05:07
  • @Ananth I made this post five years ago, so the code is long gone. It's pretty simple to finish, though, especially if you look up the Shunting Yard algorithm as noted in the comments. It's also kind of outside the scope of SO to ask people to provide complete solutions, so have a go first and post a question if you run into trouble. – TheEvilPenguin Mar 09 '15 at 21:52
  • Where can I find the `Operand` written at the top of the code snippet? – tom_mai78101 Oct 20 '15 at 05:36
2

Possibly a duplicate of:

Is there a string math evaluator in .NET?

The short answer is no, for the long answer see the link. ( I recommend 'coppercoders' solution. )

Community
  • 1
  • 1
0

Why don't you use Simple Math Parser or something is same? link text

Linh
  • 1,024
  • 2
  • 16
  • 28
0

I took a cheap way out in a recent Silverlight application by scrubbing the string with a regex (for safety) and passing it to the JavaScript evaluator. It actually works very well but it's a hack I admit.

http://josheinstein.com/blog/index.php/2010/03/mathevalconverter

Josh
  • 68,005
  • 14
  • 144
  • 156