C # разрешение "(истина и правда) или (истина или ложь)" - PullRequest
4 голосов
/ 07 июня 2011

C #: у меня есть строковая переменная, которая выглядит следующим образом:

 string a = "(true and true) or (true or false)";

Это может быть что угодно, может быть более сложным, например:

 string b = "((true and false) or (true or false) and not (true and false)) and false";

Все, что я знаю, эточто это правильно.Не может случиться, что это выражение не может быть «оценено».

Есть ли способ, которым я могу как-то это оценить?Я хотел бы знать только результат (результат) этой строки.Это означает, что мне нужно «true» или «false» вместо этой строки.

Я думаю, что могу сделать метод синтаксического анализа, который делает это, сокращая строку шаг за шагом, пока мы не получим окончательное значение, но яИнтересно, есть ли лучший подход.

Ответы [ 4 ]

10 голосов
/ 07 июня 2011

Расширяя комментарии Роба, вы можете использовать компиляцию во время выполнения вместе с поддержкой C # 4.0 dynamic и сделать что-то вроде этого:

var expression = "(true and false) or (true or false)";

var helper = "" + 
    "using System; " + 
    "public class Expression {{ public bool Eval() {{ return {0}; }} }}";

var replaced = expression.Replace("and", "&&").Replace("or", "||");

var references = new string[] { "System.dll" };
var parameters = new CompilerParameters(references, "Test.dll");
var compiler = new CSharpCodeProvider();


var results = compiler.CompileAssemblyFromSource(
    parameters, 
    String.Format(helper, replaced));

dynamic exp = Activator.CreateInstance(
    results.CompiledAssembly.GetType("Expression"));

Console.WriteLine(exp.Eval());
7 голосов
/ 07 июня 2011

Что-то вроде этого может быть?

string previous = string.Empty;
while (b != previous) 
{
     previous = b;
     b = b.Replace("true and false", "false");
     b = b.Replace("true and true", "true");
     b = b.Replace("false and true", "false");
     b = b.Replace("false and false", "false");
     b = b.Replace("false or false", "false");
     b = b.Replace("true or false", "true");
     b = b.Replace("true or true", "true");
     b = b.Replace("false or true", "true");
     b = b.Replace("(false)", "false");
     b = b.Replace("(true)", "true");
     b = b.Replace("not false", "true");
     b = b.Replace("not true", "false");
 }

Обратите внимание, что спецификация допускает неоднозначные формулировки, такие как эти:

"false and false or true"
"false and true or true"

Оба эти выражения имеют значение "true", если и вычисляются первыми, и "false", если или вычисляются первыми. Следовательно, требовать круглых скобок на каждом уровне было бы лучше. Требование оценки слева направо является еще одним вариантом, но это делает код немного более сложным.

Для тех из вас, кто может возражать против такого стиля решения для этого типа проблемы, помните, что некоторые математики считают, что вся математика может быть сведена к такого рода символьной манипуляции. сказано , что одна из основных критических замечаний Principia Mathematica * Рассела и Уайтхеда заключается в том, что в него входят формулы, имеющие слишком большое значение.

2 голосов
/ 07 июня 2011

Парсинг - ваш лучший выбор. Если вам придется проверять опечатки, это будет немного сложнее.

0 голосов
/ 07 июня 2011

C # Не имеет метода Eval или чего-то подобного, что позволяло бы вам просто выполнить такой оператор, чтобы получить окончательный результат.Если я что-то не упустил, вам придется проанализировать и сократить этот путь.

...