views:

168

answers:

5

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.

A: 

Yes:

string expression = "y=3*x + 3";
John Rasch
Somehow, I don't think that's what he wanted :)
Dean Harding
+1 Answers the question, yet funny :)
Yann Ramin
With 11.8K reputation, no one dares to vote down for giving that kind of sarcastic answer. Don't try if you have only a few K.
Khnle
The question does say "into string".
+2  A: 

Possibly a duplicate of:

http://stackoverflow.com/questions/355062/is-there-a-string-math-evaluator-in-net/392355#392355

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

A: 

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
A: 

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

Linh
A: 

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 Einstein