开发者

Sample expression Evaluator

Say I need to evaluate a expression as true or false starting from a sample input string like

True or False or ( False or True )

we suppose do not do any validation check.

Bellow we have a working sample that don't use brackets, and I need to add the brackets support...

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication4
{
    class Program
    {
        static void Main(string[] args)
        {
            var input = Console.ReadLine();

            // suppose the user introduces a valid input like:
            // True or False or ( False or True )
            var stringTokens = input.Split(" ".ToCharArray());

            List<Token> tokens = new List<Token>();

            foreach (string token in stringTokens)
            {
                tokens.Add(new Token(token));
            }

            bool result = Token.GetResult(tokens.ToArray());

            Console.WriteLine("The result is - {0}!", result);
            Console.ReadKey();
        }

        class Token
        {
            public readonly Linker Linker;
            public readonly bool? Value;

            public Token(string text)
            {
                switch (text.Trim().ToLower())
                {
                    case "true":
                        Value = true; break;
                    case "false":
                        Value = false; break;
                    case "(":
                        Linker = Program.Linker.LeftBracket; break;
                    case ")":
                        Linker = Program.Linker.RightBracket; break;
                    case "and":
                        Linker = Program.Linker.And; break;
                    case "or":
                        Linker = Program.Linker.Or; break;
                    default: break;
                }
            }

            public bool IsLinker
            { get { return !Value.HasValue; } }

            public static bool GetResult(params Token[] tokens)
            {
                bool result = true;

                Linker previousLinker = Linker.And;

                // this is some bull code...
                // please help
                foreach (var token in tokens)
                {
                    if (token.IsLinker)
                        previousLinker = token.Linker;
                    else
                    {
                        if (previousLinker == Linker.And)
                            result = result && token.Value.Value;
                        else if (previousLinker == Linker.And)
                            result = result || token.Value.Value;
                        else // brackets
                        {
                            previousLinker = Linker.And;
                            //result = result; // NO idea here...
                        }
                    }
                }
    开发者_如何学编程            return result;
            }
        }

        public enum Linker
        {
            None, And, Or,
            LeftBracket,
            RightBracket
        }
    }
}

I should mention that I can't use the Dynamic Link Library, because I already use it... in fact, my question is strongly linked with this one: Using brackets in dynamic .NET expressions

I just want to understand how to group some booleans with brackets... Thanks!


You should make GetResult function recursive.

When your foreach loop meets Linker.LeftBracket it should call GetResult(nonProcessedTokents) without the processed tokens. And when your loop meets Linker.RightBracket it'd evaluate and return the result. This method'll help to handle with nested brackets too. Something like that:

GetResult(Tokens.Skip(parsedTokensCount).Take(Tokens.Length-parsedTokensCount)

Or try this library: Flee.


This is one way of doing it using the C# compiler. (You have to secure the input string form injection)

public bool Evaluate(string value)
{
    const string code = @"
    using System;

    namespace Test
    {{
        public class TestClass
        {{
            public bool Eval()
            {{
                return {0};
            }}
        }}
    }}";
    value = value.ToLower().Replace("or", "||").Replace("and", "&&");
    using(var icc =  CodeDomProvider.CreateProvider("CSharp"))
    {
        var parameters = new CompilerParameters()
        {
            GenerateExecutable = false,
            GenerateInMemory = true
        };
        var cr = icc.CompileAssemblyFromSource(parameters, string.Format(code, value));
        var assembly = cr.CompiledAssembly;
        var sourceClass = assembly.CreateInstance("Test.TestClass");
        return (bool)sourceClass.GetType().InvokeMember("Eval", BindingFlags.InvokeMethod, null, sourceClass, null);
    }
}


I'm not sure if I understand your question, but aren't you looking for something like Reverse Polish Notation? It allows to handle such expressions without using brackets.

This algorithm explains how to translate your notation to RPN - Shunting-yard algorithm. Your problem is much simpler because you have less operators.

Some time ago I wrote something very similar: http://www.copypastecode.com/77935/ - it has some more features (i.e. it keeps order of operations). It is based on IPredicateExpression that is defined as something that takes an object and returns bool.


If you decide rolling your own isn't the easiest approach, SoftCircuits.ExpressionEvaluator on NuGet will evaluate expressions and even supports strings and custom functions or symbols. Disclaimer: I'm the one who wrote it.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜