假设我需要从类似
的示例输入字符串开始将表达式计算为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>
我只想了解如何用括号对一些布尔值进行分组...谢谢!
答案 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将评估表达式,甚至支持字符串以及自定义函数或符号。免责声明:我是写它的人。