Разбор / оценка динамического логического выражения в C # или VB? - PullRequest
8 голосов
/ 08 декабря 2008

Лучше всего было оценить выражение вроде следующего:
(А И Б) Или (А И С) Или (Не Б и С)
или
(A && B) || (A && C) || (! B && C)

Во время выполнения я планировал преобразовать приведенные выше выражения в следующее:
(Верно и неверно) или (верно и неверно) или (не неверно и не верно)
или
(True && False) || (True && False) || (! False && True)

Условия: 1) Логическое выражение не известно до времени выполнения. 2) Переменная числа и их значения неизвестны до времени выполнения. 3) Значения переменных никогда не бывают нулевыми.

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

Предложения

Спасибо.

Ответы [ 9 ]

8 голосов
/ 08 декабря 2008

Если вы используете .NET3.5, вы можете проанализировать текст и создать абстрактное синтаксическое дерево, используя классы Expression. Затем создайте подходящий экземпляр LambdaExpression и скомпилируйте его в делегат, который вы затем сможете выполнить.

Создание синтаксического анализатора и построителя синтаксического дерева для этого довольно простого грамматика - довольно интересное упражнение, и оно будет выполняться несколько быстрее, чем вызов компилятора (и, на мой взгляд, точнее).

Если вы не используете .NET3.5, то также нетрудно самостоятельно реализовать интерпретированное дерево абстрактного синтаксиса.

4 голосов
/ 08 декабря 2008

Имейте в виду: два заключительных условия, о которых вы говорите, не обязательно эквивалентны. Операторы && в C # будут использовать оценку короткого замыкания, а логический оператор And в VB - нет. Если вы хотите убедиться, что операторы эквивалентны, переведите пользователя And в AndAlso и пользователя Or в OrElse.

Для простых выражений вы, вероятно, не заметите разницу. Но если условия могут иметь побочные эффекты или если разница в производительности между ними является проблемой, это может быть важно.

3 голосов
/ 01 декабря 2012

Вы можете использовать https://github.com/mrazekv/logicalparser

Это просто библиотека для написания логических выражений (определяется таблицей прецедентов, позволяет выполнять операции И, НЕ, И и>,> =, <=, <для целочисленных переменных и = для строковых переменных) </p>

3 голосов
/ 08 декабря 2008

Вы можете сделать это легко с помощью:

  1. генератор синтаксического анализатора (такой как ANTLR, упомянутый выше), который принимает логические выражения в качестве входных данных и создает список инфиксов и
  2. код для оценки стека обратной польской нотации.

Грамматика выглядит примерно так:

program: exprList ;

exprList: expr { Append($1); }
    | expr OR exprList { Append(OR); }
    | expr AND exprList { Append(AND); }
    | NOT exprList { Append(NOT); }
    | ( exprList ) { /* Do nothing */ }
    ;

expr: var { Append($1); }
    | TRUE { Append(True); }
    | FALSE { Append(False); }
    ;

Чтобы оценить, вы делаете это:

for each item in list
    if item is symbol or truth value, push onto RPN stack
    else if item is AND, push (pop() AND pop())
    else if item is OR, push (pop() OR pop())
    else if item is NOT, push (NOT pop())

result = pop()

Для символов вы должны заменить значение истинности во время выполнения.

0 голосов
/ 04 апреля 2019

Взгляните на мою библиотеку, Провиант . Это стандартная библиотека .NET, использующая алгоритм Shunting Yard для оценки логических выражений.

Он также может генерировать таблицу истинности для ваших выражений.

Вы также можете реализовать свою собственную грамматику.

0 голосов
/ 25 апреля 2016

Это не будет лучшим ответом, но у меня сама была эта проблема некоторое время назад.

Вот мой старый код: VB.Net - вообще никаких гарантий!

https://cloud.downfight.de/index.php/s/w92i9Qq1Ia216XB

Dim BoolTermParseObjekt As New BoolTermParse
MsgBox(BoolTermParseObjekt.parseTerm("1 und (((0 oder 1 und (0 oder 4))) oder 2)").ToString)

Этот код ест строку с несколькими «(», «)», «и», «или» плюс «другие вещи» и разбивает логику на логическое значение, заменяя вещи логическими значениями. Таким образом:

Какие бы «другие вещи» я не хотел оценивать, я должен был добавить в функцию resolTerm () в комментарии "'ausführen und zurückgeben, einzelwert!" на странице 2. Там единственная оценка справа: «Если число> 1»

Привет

0 голосов
/ 08 декабря 2008

Одним из решений было бы собрать выражение в виде строки, а затем отправить его на SQL Server или в любую базу данных для оценки. Замените фактические переменные на 1 = 1 или 0 = 1 для True и False соответственно, и вы получите запрос, подобный следующему:

ВЫБРАТЬ 1 ГДЕ (1 = 1 И 0 = 1) Или (1 = 1 И 1 = 1) Или (Не 0 = 1 И 1 = 1)

Затем, когда вы запускаете запрос, вы получаете 1 обратно, когда результат равен true. Возможно, не самое элегантное решение, но оно будет работать. Многие люди, вероятно, будут советовать против этого, но я все равно собираюсь выложить это как возможное решение.

0 голосов
/ 08 декабря 2008

Если вы используете .NET 3.5, вы можете создать лямбда-выражение. Затем вы можете создать из него делегат и вызвать его как стандартный делегат / метод. В интернете много примеров про лямбда-выражения.

0 голосов
/ 08 декабря 2008

Вы можете написать простой интерпретатор / парсер. Используйте что-то вроде ANTLR и повторно используйте существующие грамматики.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...