Анализатор логических выражений в Java

Существуют ли какие-либо java-библиотеки или методы для разбора булевых выражений по частям?

Что я имею в виду, так это выражение:

T && ( F || ( F && T ) )

Его можно разбить на дерево выражений, чтобы показать, какой токен вызвал значение 'F', например, (например,что- то вроде этого):

T &&               <- rhs false
    ( F ||         <- rhs false
        ( F && T ) <- eval, false
    )

Я пытаюсь передать оценки булевых выражений непрограммистам. Я возился с Anlr, но я не мог заставить его делать много (кажется, что он немного обучается).

Я не против написать это сам, но я бы не стал изобретать велосипед.

6 ответов

Решение

Я закодировал это с помощью Javaluator.
Это не совсем вывод, который вы ищете, но я думаю, что это может быть отправной точкой.

package test;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import net.astesana.javaluator.*;

public class TreeBooleanEvaluator extends AbstractEvaluator<String> {
  /** The logical AND operator.*/
  final static Operator AND = new Operator("&&", 2, Operator.Associativity.LEFT, 2);
  /** The logical OR operator.*/
  final static Operator OR = new Operator("||", 2, Operator.Associativity.LEFT, 1);

  private static final Parameters PARAMETERS;

  static {
    // Create the evaluator's parameters
    PARAMETERS = new Parameters();
    // Add the supported operators
    PARAMETERS.add(AND);
    PARAMETERS.add(OR);
    // Add the parentheses
    PARAMETERS.addExpressionBracket(BracketPair.PARENTHESES);
  }

  public TreeBooleanEvaluator() {
    super(PARAMETERS);
  }

  @Override
  protected String toValue(String literal, Object evaluationContext) {
    return literal;
  }

  private boolean getValue(String literal) {
    if ("T".equals(literal) || literal.endsWith("=true")) return true;
    else if ("F".equals(literal) || literal.endsWith("=false")) return false;
    throw new IllegalArgumentException("Unknown literal : "+literal);
  }

  @Override
  protected String evaluate(Operator operator, Iterator<String> operands,
      Object evaluationContext) {
    List<String> tree = (List<String>) evaluationContext;
    String o1 = operands.next();
    String o2 = operands.next();
    Boolean result;
    if (operator == OR) {
      result = getValue(o1) || getValue(o2);
    } else if (operator == AND) {
      result = getValue(o1) && getValue(o2);
    } else {
      throw new IllegalArgumentException();
    }
    String eval = "("+o1+" "+operator.getSymbol()+" "+o2+")="+result;
    tree.add(eval);
    return eval;
  }

  public static void main(String[] args) {
    TreeBooleanEvaluator evaluator = new TreeBooleanEvaluator();
    doIt(evaluator, "T && ( F || ( F && T ) )");
    doIt(evaluator, "(T && T) || ( F && T )");
  }

  private static void doIt(TreeBooleanEvaluator evaluator, String expression) {
    List<String> sequence = new ArrayList<String>();
    evaluator.evaluate(expression, sequence);
    System.out.println ("Evaluation sequence for :"+expression);
    for (String string : sequence) {
      System.out.println (string);
    }
    System.out.println ();
  }
}

Вот результат:

Последовательность оценки для: T && (F || (F && T))
(F && T) = ложь
(F || (F && T) = false) = false
(T && (F || (F && T) = false) = false) = false

Последовательность оценки для: (T && T) || (F && T)
(T && T) = правда
(F && T) = ложь
((T && T) = true || (F && T) = false) = true

Вы можете сделать это с MVEL или JUEL. Оба являются библиотеками языка выражений, примеры ниже используют MVEL.

Пример:

System.out.println(MVEL.eval("true && ( false || ( false && true ) )"));

Печать: ложь

Если вы буквально хотите использовать "T" и "F", вы можете сделать это:

Map<String, Object> context = new java.util.HashMap<String, Object>();
context.put("T", true);
context.put("F", false);
System.out.println(MVEL.eval("T && ( F || ( F && T ) )", context));

Печать: ложь

Недавно я собрал библиотеку на Java специально для управления логическими выражениями: jbool_expressions.

Он включает в себя инструмент для анализа выражений из строкового ввода:

Expression<String> expr = ExprParser.parse("( ( (! C) | C) & A & B)")

Вы также можете сделать довольно простое упрощение:

Expression<String> simplified = RuleSet.simplify(expr);
System.out.println(expr);

дает

(A & B)

Если вы хотите пошагово выполнить назначение, вы можете назначить значения одно за другим. Для примера здесь

Expression<String> halfAssigned = RuleSet.assign(simplified, Collections.singletonMap("A", true));
System.out.println(halfAssigned);

шоу

B

и вы можете решить это, назначив B.

Expression<String> resolved = RuleSet.assign(halfAssigned, Collections.singletonMap("B", true));
System.out.println(resolved);

шоу

true

Не на 100% то, что вы просили, но надеюсь, что это поможет.

Проверьте BeanShell. Он имеет разбор выражений, который принимает Java-подобный синтаксис.

РЕДАКТИРОВАТЬ: Если вы не пытаетесь разобрать T && F буквально, хотя вы могли бы сделать это в BeanShell, используя литералы true а также false,

Попробуй это.

      static boolean parseBooleanExpression(String s) {
    return new Object() {

        int length = s.length(), index = 0;

        boolean match(String expect) {
            while (index < length && Character.isWhitespace(s.charAt(index)))
                ++index;
            if (index >= length)
                return false;
            if (s.startsWith(expect, index)) {
                index += expect.length();
                return true;
            }
            return false;
        }

        boolean element() {
            if (match("T"))
                return true;
            else if (match("F"))
                return false;
            else if (match("(")) {
                boolean result = expression();
                if (!match(")"))
                    throw new RuntimeException("')' expected");
                return result;
            } else
                throw new RuntimeException("unknown token");
        }

        boolean term() {
            if (match("!"))
                return !element();
            else
                return element();
        }

        boolean factor() {
            boolean result = term();
            while (match("&&"))
                result &= term();
            return result;
        }

        boolean expression() {
            boolean result = factor();
            while (match("||"))
                result |= factor();
            return result;
        }

        boolean parse() {
            boolean result = expression();
            if (index < length)
                throw new RuntimeException(
                    "extra string '" + s.substring(index) + "'");
            return result;
        }
    }.parse();
}

А также

      public static void main(String[] args) {
    String s = "T && ( F || ( F && T ) )";
    boolean result = parseBooleanExpression(s);
    System.out.println(result);
}

выход:

      false

Синтаксис:

       expression = factor { "||" factor }
 factor     = term { "&&" term }
 term       = [ "!" ] element
 element    = "T" | "F" | "(" expression ")"

mXparser обрабатывает логические операторы - пожалуйста, найдите несколько примеров

Пример 1:

import org.mariuszgromada.math.mxparser.*;
...
...
Expression e = new Expression("1 && (0 || (0 && 1))");
System.out.println(e.getExpressionString() + " = " + e.calculate());

Результат 1:

1 && (0 || (0 && 1)) = 0.0

Пример 2:

import org.mariuszgromada.math.mxparser.*;
...
...
Constant T = new Constant("T = 1");
Constant F = new Constant("F = 0");
Expression e = new Expression("T && (F || (F && T))", T, F);
System.out.println(e.getExpressionString() + " = " + e.calculate());

Результат 2:

T && (F || (F && T)) = 0.0

Для получения более подробной информации, пожалуйста, следуйте инструкциям mXparser.

С наилучшими пожеланиями

Другие вопросы по тегам