样本表达式Evaluator

时间:2011-09-07 16:55:46

标签: .net algorithm

假设我需要从类似
的示例输入字符串开始将表达式计算为true或false True or False or ( False or True )
我们假设不做任何验证检查。

Bellow我们有一个不使用括号的工作样本,我需要添加括号支持...

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
        }
    }
}

我应该提到我不能使用动态链接库,因为我已经使用它了......事实上,我的问题与这个问题密切相关:Using brackets in dynamic .NET expressions < / p>

我只想了解如何用括号对一些布尔值进行分组...谢谢!

4 个答案:

答案 0 :(得分:2)

你应该使GetResult函数递归。

当你的foreach循环遇到Linker.LeftBracket时,它应该调用GetResult(nonProcessedTokents)而没有处理过的标记。当你的循环遇到Linker.RightBracket时,它会评估并返回结果。此方法也有助于使用嵌套括号进行处理。这样的事情:

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

或者尝试使用此库:Flee

答案 1 :(得分:1)

这是使用C#编译器执行此操作的一种方法。 (您必须确保输入字符串形式注入)

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);
    }
}

答案 2 :(得分:0)

我不确定我是否理解你的问题,但你不是在找Reverse Polish Notation之类的东西吗?它允许在不使用括号的情况下处理这些表达式。

此算法说明了如何将您的符号转换为RPN - Shunting-yard algorithm。您的问题要简单得多,因为您的运营商较少。

前段时间我写了一些非常类似的东西:http://www.copypastecode.com/77935/ - 它有一些更多的功能(即它保持操作顺序)。它基于IPredicateExpression,它被定义为接受对象并返回bool的东西。

答案 3 :(得分:0)

如果您认为滚动不是最简单的方法,则NuGet上的SoftCircuits.ExpressionEvaluator将评估表达式,甚至支持字符串以及自定义函数或符号。免责声明:我是写它的人。