boolean expression parser in java - java

Are there any java libraries or techniques to parsing boolean expressions piecemeal?
What I mean is given an expression like this:
T && ( F || ( F && T ) )
It could be broken down into a expression tree to show which token caused the 'F' value, like so (maybe something like this):
T && <- rhs false
( F || <- rhs false
( F && T ) <- eval, false
)
I am trying to communicate boolean expression evaluations to non-programmers. I have poked around with Anlr, but I couldn't get it to do much (it seems to have a bit of a learning curve).
I'm not opposed to writing it myself, but I'd rather not reinvent the wheel.

You could do this with MVEL or JUEL. Both are expression language libraries, examples below are using MVEL.
Example:
System.out.println(MVEL.eval("true && ( false || ( false && true ) )"));
Prints:
false
If you literally want to use 'T' and 'F' you can do this:
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));
Prints:
false

I've coded this using Javaluator.
It's not exactly the output you are looking for, but I think it could be a start point.
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 ();
}
}
Here is the ouput:
Evaluation sequence for :T && ( F || ( F && T ) )
(F && T)=false
(F || (F && T)=false)=false
(T && (F || (F && T)=false)=false)=false
Evaluation sequence for :(T && T) || ( F && T )
(T && T)=true
(F && T)=false
((T && T)=true || (F && T)=false)=true

I recently put together a library in Java specifically to manipulate boolean expressions: jbool_expressions.
It includes a tool too parse expressions out of string input:
Expression<String> expr = ExprParser.parse("( ( (! C) | C) & A & B)")
You can also do some fairly simple simplification:
Expression<String> simplified = RuleSet.simplify(expr);
System.out.println(expr);
gives
(A & B)
If you wanted to step through the assignment then, you could assign values one by one. For the example here,
Expression<String> halfAssigned = RuleSet.assign(simplified, Collections.singletonMap("A", true));
System.out.println(halfAssigned);
shows
B
and you could resolve it by assigning B.
Expression<String> resolved = RuleSet.assign(halfAssigned, Collections.singletonMap("B", true));
System.out.println(resolved);
shows
true
Not 100% what you were asking for, but hope it helps.

Check out BeanShell. It has expression parsing that accepts Java-like syntax.
EDIT: Unless you're trying to actually parse T && F literally, though you could do this in BeanShell using the literals true and false.

Try this.
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();
}
And
public static void main(String[] args) {
String s = "T && ( F || ( F && T ) )";
boolean result = parseBooleanExpression(s);
System.out.println(result);
}
output:
false
The syntax is
expression = factor { "||" factor }
factor = term { "&&" term }
term = [ "!" ] element
element = "T" | "F" | "(" expression ")"

mXparser handles Boolean operators - please find few examples
Example 1:
import org.mariuszgromada.math.mxparser.*;
...
...
Expression e = new Expression("1 && (0 || (0 && 1))");
System.out.println(e.getExpressionString() + " = " + e.calculate());
Result 1:
1 && (0 || (0 && 1)) = 0.0
Example 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());
Result 2:
T && (F || (F && T)) = 0.0
For more details please follow mXparser tutorial.
Best regards

Related

Android Matcher.replaceAll/replaceFirst problem with groups count > 9

I've found some problem with Matcher.replaceFirst/replaceAll when subgroup count in regex is more than 9...
simple example:
String res = "abcdefghij".replaceFirst("(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)", "$1 $2 $3 $4 $5 $6 $7 $8 $9 $10");
Expected result is "a b c d e f g h i j" but got "a b c d e f g h i a0" string.
This problem can reproduced in Android runtime, but on local unit tests with desktop java it works well.
When I tried to debug it step by step, I've found following ugly code in Android sources of Matcher class:
private void appendEvaluated(StringBuffer buffer, String s) {
boolean escape = false;
boolean dollar = false;
boolean escapeNamedGroup = false;
int escapeNamedGroupStart = -1;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '\\' && !escape) {
escape = true;
} else if (c == '$' && !escape) {
dollar = true;
} else if (c >= '0' && c <= '9' && dollar) { //<<<<------ WHAT IS IT?!
buffer.append(group(c - '0'));
dollar = false;
} else if (c == '{' && dollar) {
escapeNamedGroup = true;
escapeNamedGroupStart = i;
} else if (c == '}' && dollar && escapeNamedGroup) {
String namedGroupName =
s.substring(escapeNamedGroupStart + 1, i);
buffer.append(group(namedGroupName));
dollar = false;
escapeNamedGroup = false;
} else if (c != '}' && dollar && escapeNamedGroup) {
continue;
} else {
buffer.append(c);
dollar = false;
escape = false;
escapeNamedGroup = false;
}
}
if (escape) {
throw new IllegalArgumentException("character to be escaped is missing");
}
if (dollar) {
throw new IllegalArgumentException("Illegal group reference: group index is missing");
}
if (escapeNamedGroup) {
throw new IllegalArgumentException("Missing ending brace '}' from replacement string");
}
}
this is part of SDK API 29... I've checked API 30 level, it has same code.
maybe someone already solve this problem?
I think it needs to create custom replacer with more correct logic...

How to replace expression by String in JavaParser AST

Suppose I have expression "(a == b || a == c) && (d == e)". How can I replace subexpression by custom String e.g. how can I replace a == b by a.equals(b)?
Solution based on #Andreas suggestion
public static void main(String[] args) {
String strExpr = "(get(a == b) || b == c ) && ( a == b ? b == c : c == d)";
Expression expr = StaticJavaParser.parseExpression(strExpr);
EnclosedExpr parentExpr = addParentExpr(expr);
processExpr(parentExpr);
expr = removeParentExpr(parentExpr);
// OUTPUT: (get(a.equals(b)) || b.equals(c)) && (a.equals(b) ? b.equals(c) : c.equals(d))
System.out.println(expr);
}
processing
private static void processExpr(Expression expr) {
expr.stream()
.filter(node -> node instanceof Expression)
.map(node -> ( Expression ) node)
.filter(Expression::isBinaryExpr)
.map(Expression::asBinaryExpr)
.filter(binaryExpr -> binaryExpr.getOperator() == Operator.EQUALS)
.forEach(binaryExpr -> binaryExpr.getParentNode().ifPresent(node -> {
node.replace(binaryExpr, equalsExpr(
binaryExpr.getLeft(), binaryExpr.getRight()));
}));
}
helper methods
private static EnclosedExpr addParentExpr(Expression expr) {
EnclosedExpr enclosedExpr = new EnclosedExpr();
enclosedExpr.setInner(expr);
return enclosedExpr;
}
private static Expression removeParentExpr(EnclosedExpr parentExpr) {
Expression expr = parentExpr.getInner();
parentExpr.remove(expr);
return expr;
}
private static MethodCallExpr equalsExpr(Expression leftExpr, Expression rightExpr) {
return new MethodCallExpr(leftExpr, "equals", new NodeList<>(rightExpr));
}
Since StaticJavaParser is slow, there is also an option to use JavaParser with ParseConfiguration to disable post processing and validation (fast parsing).
JavaParser javaParser = new JavaParser(new ParserConfiguration()
.setLanguageLevel(LanguageLevel.RAW));

Making a password verification into a class

I have a program grabbing a password from the user, then it checks if the conditions are met or not then outputs "Valid Password" or "Invalid Password". This works, and I was able to turn the verification aspect into a method in the same program and it works, but I want to make it into a class where I can just say if( validate(pw) == true ) ... or at least if( v.getValidation() == true ) ... in any program and it will test my conditions. I've used custom classes before but for some reason everything I try does not work on this one, I've been at it for days.
Here's my method:
public boolean validate( String pw )
{
boolean l = false, u = false, lo = false, d = false, r = true;
if( pw.length() >= 6 )
{ l = true; }
for( int i = 0; i < pw.length(); i++ )
{
if( Character.isUpperCase( pw.charAt(i) ) )
{ u = true; }
if( Character.isLowerCase( pw.charAt(i) ) )
{ lo = true; }
if( Character.isDigit( pw.charAt(i) ) )
{ d = true; }
}
if( l == false || u == false || lo == false || d == false )
{ r = false; }
return r;
}
Edit:
Thank you all for your input, this is what it came out to in the end:
public class Password
{
public static boolean validate( String pw )
{
boolean result = false;
int upper = 0, lower = 0, digit = 0;
if( pw.length() >= 6 )
{
for( int i = 0; i < pw.length(); i++ )
{
if( Character.isUpperCase( pw.charAt(i) ) )
{ upper++; }
if( Character.isLowerCase( pw.charAt(i) ) )
{ lower++; }
if( Character.isDigit( pw.charAt(i) ) )
{ digit++; }
}
}
if( upper >= 1 && lower >= 1 && digit >= 1 )
{ result = true; }
return result;
}
}
You do not need to make a whole class for this. You can do something like:
public static void main(String[] args) {
boolean valid = validate("PassWord22");
}
public static boolean validate( String pw ) {}
Also some notes on your method:
You don't need to do l == true or l == false in your if statement. You can simply do:
if( !l || !u || !lo || !d )
{ r = false; }
In fact you can just return
return l && u && lo && d;
If the length is not 6 or greater, simply return false. This will save checking all the letters in the String
I would come up with better variable names. Single/two letter variable names makes it very hard to tell what they represent, and easy to mix up. (instead of l you could have length and instead of u you could have upper)
Also this can be easier solved with regex and String.matches():
public static boolean validate(String pw) {
String pattern = "^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).+$";
return (pw.length() > 5 && pw.matches(pattern));
}
I got it working, turned out to be an error in the code that the compiler was not picking up. I wanted to delete the question but they wont let me for some reason. So in case you're curious this is what my class looks like functioning:
public class Password
{
private String pw;
public Password()
{
pw = "";
}
public Password( String pw )
{
this.pw = pw;
}
public boolean getPassword( String pw )
{
boolean l = false, u = false, lo = false, d = false, r = true;
if( pw.length() >= 6 )
{ l = true; }
for( int i = 0; i < pw.length(); i++ )
{
if( Character.isUpperCase( pw.charAt(i) ) )
{ u = true; }
if( Character.isLowerCase( pw.charAt(i) ) )
{ lo = true; }
if( Character.isDigit( pw.charAt(i) ) )
{ d = true; }
}
if( l == false || u == false || lo == false || d == false )
{ r = false; }
return r;
}

Recursion - Expressions that evaluate to target

I am trying to understand recursion and solve the problem with
operators = ['','*', "+"]
input : "2224"
target : 24
output = {"22+2", "2+22", "24"}
Here's the code that I came up with. But it produces invalid output.
static List<String> output = new ArrayList<>();
static String[] generate_all_expressions(String s, long target) {
getExpressionsRecur(s, target, 0, null, 0);
String[] out = new String[output.size()];
return output.toArray(out);
}
static void getExpressionsRecur(String s, long target, int currentValue, String currExpression, int currIndex) {
if (currIndex == s.length()){
if (currentValue == target) {
output.add(currExpression);
}
return;
}
if (currentValue == target) {
output.add(currExpression);
return;
}
int currentPart = Integer.valueOf(s.substring(currIndex, currIndex+1));
if (currIndex == 0) {
getExpressionsRecur(s, target, currentPart, String.valueOf(currentPart), currIndex+1);
} else {
int value = Integer.valueOf(String.valueOf(currentValue) + String.valueOf(currentPart));
getExpressionsRecur(s, target, value , currExpression + "" + currentPart, currIndex+1);
getExpressionsRecur(s, target, (currentValue * currentPart), currExpression + "*" + currentPart, currIndex+1);
getExpressionsRecur(s, target, (currentValue + currentPart), currExpression + "+" + currentPart, currIndex+1);
}
}
It produces:
{22+2, 2*2+2*4, 2+2+2*4}
Can someone help me spot the errors?
First rethink your recursion since you're not hitting every case.
Write out cases if you need to, maybe start with a 3 digit number since there are less cases; In your code, for example, "24" is never evaluated on it's own.
You are calculating value wrongly for concatenation case. 22*2 will become 22*24.But you are saying this new expression has a value of 444 (should be 528) . You can't really use current value. Probably you can restructure your recursion to make it easier.
You can use this Expression object I threw together in replace of your expression String... call expression.toString() and expression.value() as necessary. But still you'll need changes to your basic recursion structure even after implementing this or similar Expression Object.
public class Expression{
Expression lExpression;
String lValue;
Expression rExpression;
String operator;
public Expression(String expression) {
int multIndex = expression.indexOf("*");
int addIndex = expression.indexOf("+");
if(multIndex == -1 && addIndex == -1) {
this.lExpression = new Expression(Integer.valueOf(expression));
return;
}
if(multIndex != -1 && multIndex < addIndex) {
this.lExpression = new Expression(expression.substring(0, addIndex));
this.operator = expression.substring(addIndex, addIndex+1);
this.rExpression = new Expression(expression.substring(addIndex+1));
}else {
if(addIndex == -1) {
addIndex = Integer.MAX_VALUE;
}
if(multIndex == -1) {
multIndex = Integer.MAX_VALUE;
}
int opIndex = multIndex < addIndex ? multIndex : addIndex;
this.lExpression = new Expression(expression.substring(0, opIndex));
this.operator = expression.substring(opIndex, opIndex+1);
this.rExpression = new Expression(expression.substring(opIndex+1)); }
}
public Expression(int value) {
this.lValue = String.valueOf(value);
this.lExpression = null;
this.rExpression = null;
this.operator = null;
}
#Override
public String toString() {
return (lExpression!=null ? lExpression : lValue) + (operator !=null ? operator: "") + (rExpression!=null ? rExpression : "");
}
public int value() {
if(lExpression == null) {
return Integer.valueOf(lValue);
}
if("*".equals(operator)) {
return lExpression.value() * rExpression.value() ;
}
if("+".equals(operator)) {
return lExpression.value() + rExpression.value();
}
return lExpression.value();
}
}

Java Expression Parser & Calculator Shunting Yard Algorithm

So the task is to create our own parser for a expression calculator. For Example:
Input: 3+2*1-6/3
Output: 3
Input: 3++2
Output: Invalid Expression
Input: -5+2
Output: -3
Input: 5--2
Output: 7
The code here solves a part of the problem except that it has a fixed input and negative values cannot be solved, And I'm not quite sure yet if it really does solve the expression with operator precedence.
but I already modified it to get an input expression from the user.
and I've been wondering for hours how to implement the solving for negative values. help anyone?
NO JAVASCRIPT ENGINE PLEASE.
here's the current code
import java.util.*;
public class ExpressionParser
{
// Associativity constants for operators
private static final int LEFT_ASSOC = 0;
private static final int RIGHT_ASSOC = 1;
// Operators
private static final Map<String, int[]> OPERATORS = new HashMap<String, int[]>();
static
{
// Map<"token", []{precendence, associativity}>
OPERATORS.put("+", new int[] { 0, LEFT_ASSOC });
OPERATORS.put("-", new int[] { 0, LEFT_ASSOC });
OPERATORS.put("*", new int[] { 5, LEFT_ASSOC });
OPERATORS.put("/", new int[] { 5, LEFT_ASSOC });
}
// Test if token is an operator
private static boolean isOperator(String token)
{
return OPERATORS.containsKey(token);
}
// Test associativity of operator token
private static boolean isAssociative(String token, int type)
{
if (!isOperator(token))
{
throw new IllegalArgumentException("Invalid token: " + token);
}
if (OPERATORS.get(token)[1] == type) {
return true;
}
return false;
}
// Compare precedence of operators.
private static final int cmpPrecedence(String token1, String token2)
{
if (!isOperator(token1) || !isOperator(token2))
{
throw new IllegalArgumentException("Invalid tokens: " + token1
+ " " + token2);
}
return OPERATORS.get(token1)[0] - OPERATORS.get(token2)[0];
}
// Convert infix expression format into reverse Polish notation
public static String[] expToRPN(String[] inputTokens)
{
ArrayList<String> out = new ArrayList<String>();
Stack<String> stack = new Stack<String>();
// For each token
for (String token : inputTokens)
{
// If token is an operator
if (isOperator(token))
{
// While stack not empty AND stack top element
// is an operator
while (!stack.empty() && isOperator(stack.peek()))
{
if ((isAssociative(token, LEFT_ASSOC) &&
cmpPrecedence(token, stack.peek()) <= 0) ||
(isAssociative(token, RIGHT_ASSOC) &&
cmpPrecedence(token, stack.peek()) < 0))
{
out.add(stack.pop());
continue;
}
break;
}
// Push the new operator on the stack
stack.push(token);
}
// If token is a left bracket '('
else if (token.equals("("))
{
stack.push(token); //
}
// If token is a right bracket ')'
else if (token.equals(")"))
{
while (!stack.empty() && !stack.peek().equals("("))
{
out.add(stack.pop());
}
stack.pop();
}
// If token is a number
else
{
// if(!isOperator(stack.peek())){
// out.add(String.valueOf(token*10));
// }
out.add(token);
}
}
while (!stack.empty())
{
out.add(stack.pop());
}
String[] output = new String[out.size()];
return out.toArray(output);
}
public static double RPNtoDouble(String[] tokens)
{
Stack<String> stack = new Stack<String>();
// For each token
for (String token : tokens) //for each
{
// If the token is a value push it onto the stack
if (!isOperator(token))
{
stack.push(token);
}
else
{
// Token is an operator: pop top two entries
Double d2 = Double.valueOf( stack.pop() );
Double d1 = Double.valueOf( stack.pop() );
//Get the result
Double result = token.compareTo("*") == 0 ? d1 * d2 :
token.compareTo("/") == 0 ? d1 / d2 :
token.compareTo("+") == 0 ? d1 + d2 :
d1 - d2;
// Push result onto stack
stack.push( String.valueOf( result ));
}
}
return Double.valueOf(stack.pop());
}
public static void main(String[] args) throws Exception{
Scanner in = new Scanner(System.in);
String reg = "((?<=[<=|>=|==|\\+|\\*|\\-|<|>|/|=])|(?=[<=|>=|==|\\+|\\*|\\-|<|>|/|=]))";
while(true){
try{
System.out.println("Enter Your Expression");
//String[] input = "( 1 + 2 ) * ( 3 / 4 ) - ( 5 + 6 )".split(" ");
String[] input = in.nextLine() .split(reg);
String[] output = expToRPN(input);
// Build output RPN string minus the commas
System.out.print("Stack: ");
for (String token : output) {
System.out.print("[ ");System.out.print(token + " "); System.out.print("]");
}
System.out.println(" ");
// Feed the RPN string to RPNtoDouble to give result
Double result = RPNtoDouble( output );
System.out.println("Answer= " + result);
}catch (NumberFormatException | EmptyStackException nfe){
System.out.println("INVALID EXPRESSION"); }
}
}
}
UPDATED CODE:
Added: unaryToexp() function.
what I wanted to do was that everytime a " - " occurs, the code treats it as a binary by changing it to " _ " as another operator and this operator solves multiplies thing by -1 (what I wanted first was to add [-1] and [*] to the rpn stack). still got problems here.
compiler says:
Enter Your Expression
-5+3
Stack: [ ][ 5 ][ - ][ 3 ][ + ]
Exception in thread "main" java.lang.NumberFormatException: empty String
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:10 11)
at java.lang.Double.valueOf(Double.java:504)
at ExpressionParser.RPNtoDouble(ExpressionParser.java:160)
at ExpressionParser.main(ExpressionParser.java:194)*
I think it has something to do with the Double d1 = Double.valueOf( stack.pop() ); cause it still pops another two values, where I only need one for a solving a unary operator. any help?
public class ExpressionParser
{
// Associativity constants for operators
private static final int LEFT_ASSOC = 0;
private static final int RIGHT_ASSOC = 1;
// Operators
private static final Map<String, int[]> OPERATORS = new HashMap<String, int[]>();
static
{
// Map<"token", []{precendence, associativity}>
OPERATORS.put("-", new int[] { 0, LEFT_ASSOC });
OPERATORS.put("+", new int[] { 0, LEFT_ASSOC });
OPERATORS.put("*", new int[] { 5, LEFT_ASSOC });
OPERATORS.put("/", new int[] { 5, LEFT_ASSOC });
OPERATORS.put("_", new int[] { 5, RIGHT_ASSOC });
}
// Test if token is an operator
private static boolean isOperator(String token)
{
return OPERATORS.containsKey(token);
}
// Test associativity of operator token
private static boolean isAssociative(String token, int type)
{
if (!isOperator(token))
{
throw new IllegalArgumentException("Invalid token: " + token);
}
if (OPERATORS.get(token)[1] == type) {
return true;
}
return false;
}
// Compare precedence of operators.
private static final int cmpPrecedence(String token1, String token2)
{
if (!isOperator(token1) || !isOperator(token2))
{
throw new IllegalArgumentException("Invalid tokens: " + token1
+ " " + token2);
}
return OPERATORS.get(token1)[0] - OPERATORS.get(token2)[0];
}
// CONVERT UNARY OPERATORS
public static String[] unaryToexp(String[] inputTokens)
{
ArrayList<String> out = new ArrayList<String>();
Stack<String> stack = new Stack<String>();
//if token is an unary minus
for (String token : inputTokens)
{
if( ((token == "-") && (isOperator(stack.peek()) || stack.empty() ))){ //
token = "_";
}
else if (token == "-"){
token = "-";
}
out.add(token);
while (!stack.empty())
{
out.add(stack.pop());
}
}
String[] output = new String[out.size()];
return out.toArray(output);
}
// Convert infix expression format into reverse Polish notation
public static String[] expToRPN(String[] inputTokens)
{
ArrayList<String> out = new ArrayList<String>();
Stack<String> stack = new Stack<String>();
// For each token
for (String token : inputTokens)
{
// If token is an operator
if (isOperator(token))
{
// While stack not empty AND stack top element
// is an operator
while (!stack.empty() && isOperator(stack.peek()))
{
if ((isAssociative(token, LEFT_ASSOC) &&
cmpPrecedence(token, stack.peek()) <= 0) ||
(isAssociative(token, RIGHT_ASSOC) &&
cmpPrecedence(token, stack.peek()) < 0))
{
out.add(stack.pop());
continue;
}
break;
}
// Push the new operator on the stack
stack.push(token);
}
// If token is a left bracket '('
else if (token.equals("("))
{
stack.push(token); //
}
// If token is a right bracket ')'
else if (token.equals(")"))
{
while (!stack.empty() && !stack.peek().equals("("))
{
out.add(stack.pop());
}
stack.pop();
}
// If token is a number
else
{
out.add(token);
}
}
while (!stack.empty())
{
out.add(stack.pop());
}
String[] output = new String[out.size()];
return out.toArray(output);
}
public static double RPNtoDouble(String[] tokens)
{
Stack<String> stack = new Stack<String>();
// For each token
for (String token : tokens)
{
// If the token is a value push it onto the stack
if (!isOperator(token))
{
stack.push(token);
}
else
{
// Token is an operator: pop top two entries
Double d2 = Double.valueOf( stack.pop() );
Double d1 = Double.valueOf( stack.pop() );
//Get the result
Double result = token.compareTo("_") == 0 ? d2 * -1 :
token.compareTo("*") == 0 ? d1 * d2 :
token.compareTo("/") == 0 ? d1 / d2 :
token.compareTo("+") == 0 ? d1 + d2 :
d1 - d2;
// Push result onto stack
stack.push( String.valueOf( result ));
}
}
return Double.valueOf(stack.pop());
}
public static void main(String[] args) throws Exception{
Scanner in = new Scanner(System.in);
String reg = "((?<=[<=|>=|==|\\+|\\*|\\-|\\_|<|>|/|=])|(?=[<=|>=|==|\\+|\\*|\\-|<|>|/|=]))";
while(true){
//try{
System.out.println("Enter Your Expression");
//String[] input = "( 1 + 2 ) * ( 3 / 4 ) - ( 5 + 6 )".split(" ");
String[] input = in.nextLine() .split(reg);
String[] unary = unaryToexp(input); //.split(reg);
String[] output = expToRPN(unary);
// Build output RPN string minus the commas
System.out.print("Stack: ");
for (String token : output) {
System.out.print("[ ");System.out.print(token); System.out.print(" ]");
}
System.out.println(" ");
// Feed the RPN string to RPNtoDouble to give result
Double result = RPNtoDouble( output );
System.out.println("Answer= " + result);
//}catch (){
//System.out.println("INVALID EXPRESSION"); }
}
}
}
Here you are:
private static final ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
public static String eval(String matlab_expression){
if(matlab_expression == null){
return "NULL";
}
String js_parsable_expression = matlab_expression
.replaceAll("\\((\\-?\\d+)\\)\\^(\\-?\\d+)", "(Math.pow($1,$2))")
.replaceAll("(\\d+)\\^(\\-?\\d+)", "Math.pow($1,$2)");
try{
return engine.eval(js_parsable_expression).toString();
}catch(javax.script.ScriptException e1){
return null; // Invalid Expression
}
}
Couldn't you use the javascript scripting engine? (you would need a bit of tweaking for the 5--2 expression) The code below outputs:
3+2*1-6/3 = 3.0
3++2 = Invalid Expression
-5+2 = -3.0
5--2 = 7.0
Code:
public class Test1 {
static ScriptEngine engine;
public static void main(String[] args) throws Exception {
engine = new ScriptEngineManager().getEngineByName("JavaScript");
printValue("3+2*1-6/3");
printValue("3++2");
printValue("-5+2");
printValue("5--2");
}
private static void printValue(String expression) {
String adjustedExpression = expression.replaceAll("--", "- -");
try {
System.out.println(expression + " = " + engine.eval(adjustedExpression));
} catch (ScriptException e) {
System.out.println(expression + " = Invalid Expression");
}
}
}
Rather than re-invent the wheel you could use a parser generator such as JavaCC or antlr, which is specifically designed for this kind of task. This is a nice example of a simple expression parser and evaluator in a couple of dozen lines of JavaCC.
Take a look at some examples and try to find a rule how to distinguish negative values from operators.
A rule like:
if (token is + or -) and next token is a number
and
(the previous token was empty
or the prvious token was ')' or another operator)
then it is a sign to the current value.
You could iterate through your original token list and create a new token list based on this rules.
I have just written such an expression evaluator and have an iterator for tokenizing expressions at hand. plan to publish it after some extensions on GitHub.
EDIT: Here is the iterator, the references and calls should be clear, it is a bit more complex because of support for variables/functions and multi-character operators:
private class Tokenizer implements Iterator<String> {
private int pos = 0;
private String input;
private String previousToken;
public Tokenizer(String input) {
this.input = input;
}
#Override
public boolean hasNext() {
return (pos < input.length());
}
private char peekNextChar() {
if (pos < (input.length() - 1)) {
return input.charAt(pos + 1);
} else {
return 0;
}
}
#Override
public String next() {
StringBuilder token = new StringBuilder();
if (pos >= input.length()) {
return previousToken = null;
}
char ch = input.charAt(pos);
while (Character.isWhitespace(ch) && pos < input.length()) {
ch = input.charAt(++pos);
}
if (Character.isDigit(ch)) {
while ((Character.isDigit(ch) || ch == decimalSeparator)
&& (pos < input.length())) {
token.append(input.charAt(pos++));
ch = pos == input.length() ? 0 : input.charAt(pos);
}
} else if (ch == minusSign
&& Character.isDigit(peekNextChar())
&& ("(".equals(previousToken) || ",".equals(previousToken)
|| previousToken == null || operators
.containsKey(previousToken))) {
token.append(minusSign);
pos++;
token.append(next());
} else if (Character.isLetter(ch)) {
while (Character.isLetter(ch) && (pos < input.length())) {
token.append(input.charAt(pos++));
ch = pos == input.length() ? 0 : input.charAt(pos);
}
} else if (ch == '(' || ch == ')' || ch == ',') {
token.append(ch);
pos++;
} else {
while (!Character.isLetter(ch) && !Character.isDigit(ch)
&& !Character.isWhitespace(ch) && ch != '('
&& ch != ')' && ch != ',' && (pos < input.length())) {
token.append(input.charAt(pos));
pos++;
ch = pos == input.length() ? 0 : input.charAt(pos);
if (ch == minusSign) {
break;
}
}
if (!operators.containsKey(token.toString())) {
throw new ExpressionException("Unknown operator '" + token
+ "' at position " + (pos - token.length() + 1));
}
}
return previousToken = token.toString();
}
#Override
public void remove() {
throw new ExpressionException("remove() not supported");
}
}

Categories

Resources