I'm looking for an evaluator for simple condition expressions.
Expressions should include variables (read only), strings, numbers and some basic operators.
E.g. expressions something like this:
${a} == "Peter" && ( ${b} == null || ${c} > 10 )
So far i implemented a rather "magical" parser that returns an AST that i can evaluate, but i can't believe that i'm the first one to solve that problem.
What existing code could i use instead?
Have you looked at MVEL? They provide a getting started guide and performance analysis.
Here's one of their simple examples:
// The compiled expression is serializable and can be cached for re-use.
CompiledExpression compiled = MVEL.compileExpression("x * y");
Map vars = new HashMap();
vars.put("x", new Integer(5));
vars.put("y", new Integer(10));
// Executes the compiled expression
Integer result = (Integer) MVEL.executeExpression(compiled, vars);
assert result.intValue() == 50;
Also (answering my own question) MVEL seems to provide some support for bytecode generation.
Other alternatives, culling from the above answers and my own:
Java Expression Parser (JEP) -- and note there is an old version available for free
Apache Commons JEXL
With regard to Rhino, here's a dude who did some arithmetic evaluation in that context (looks messy)
Sounds like JEXL might work well for you. Check out its syntax reference.
What about SPEL (Spring Expression Lang); http://static.springsource.org/spring/docs/3.0.x/reference/expressions.html
Why don't you use Rhino? It's a JavaScript engine already present inside the JDK.
It can evaluate whatever you like to write in JS.. take a look here
This simple recursive descent parser evaluates constants as named functions having no parameters.
A very simple and easy to use alternative with a lot of built in excel functions for string, date and number formatting.
The library also allows easy addition of custom functions. A lot of examples available on the git page. A simple example using variables
ExpressionsEvaluator evalExpr = ExpressionsFactory.create("LEFT(City, 3)");
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("City", "New York");
assertEquals("New", evalExpr.eval(variables));
Here is a little library I've worked on that supports expression evaluation (including variables, strings, boolean, etc...).
A little example :
String expression = "EXP(var)";
ExpressionEvaluator evaluator = new ExpressionEvaluator();
evaluator.putVariable(new Variable("var", VariableType.NUMBER, new BigDecimal(20)));
System.out.println("Value of exp(var) : " + evaluator.evaluate(expression).getValue());
Related
I'm working on a tool in the context of a java project to evaluate a custom domain specific, rule-like expression like
min-5 avg datalist > Number
with the individual tokens meaning the following:
min-5 : optional minimum (or maximum, in that case max-5) occurences of the following term
avg : an optional aggregation function which operates on the following token datalist (can also be sum or anything similar)
datalist : A list of data (type: integer/ double) which will be available before the evaluation of the entire expression starts, can be reduced to a single value by the preceding aggregation function
operator: conditional operator < or > or =
Number: value for the conditional operator
Note(s):
The optional amount of occurrences and the aggregation can not happen both, that would make no sense.
There can be multiple of the above expressions, chained with and/or
These expressions are external input, not pre-defined
The evaluation of this expression should output a boolean
As I am rather new to expression evaluation / parsing I am searching for an elegant way to solve this, possibly with a java framework/tool.
What I've tried so far:
Parsing by hand which turned out not so nicely
Trying to use Janino Expression Evaluator, but I don't know how to handle this programmatically
I am searching for a solution to solve this in an elegant way, I am thankful for any suggestions
what you try to do is a DSL (domain specific language) and the elegant way to solve your issue is to create a grammar for yuor specific language that help you on parsing function.
Take a look at JavaCC or Antlr.
There is a question with the same title like this on stackoverflow here, but I wanted to ask if it is possible to do something similar to this in Java.
I wanted to make something similar to desmos, just like that guy did in Javascript,but i want to make it in Java using lwjgl 2. I am new to Java and I'd like to know if it is possible to convert a piece of string into a method. Is it possible?
I have looked for possible options and I found out that your can make your own Java eval() method. But I don't want to replace the x in the string for every pixel of the window-width.
Thanks in advance.
What you need is an engine/library that can evaluate expressions, defined as string at execution time. If you wrap the evaluation code into function call (e.g. lambda function), you will get what you need.
Option 1: You can use exp4j. exp4j is a small footprint library, capable of evaluating expressions and functions at execution time. Here is an example:
Expression e = new ExpressionBuilder("3 * sin(y) - 2 / (x - 2)")
.variables("x", "y")
.build()
.setVariable("x", 2.3)
.setVariable("y", 3.14);
double result = e.evaluate();
Option 2: You can use the Java's script engine. You can use it to evaluate expressions defined, for example, in JavaScript:
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("js");
Object result = engine.eval("sin(1.25)");
Option 3: Compile to native Java. With this approach, you use template to generate .java file with a class that contains your expression. Than you call the Java compiler. This approach has the drawback that has some complexity in the implementation and some initial latency (until the class is compiled), but the performance is the best. Here are some links to explore:
Create dynamic applications with javax.tools
In particular javax.tools.Compiler
Note of Caution Whatever approach you chose, have in mind that you need to think about the security. Allowing the user to enter code which can be evaluated without security restrictions could be very dangerous.
Currently trying to do a reverse polish calculator for one of my Uni homework tasks.
I have the program working fine when using a bunch of if/else statements to work out which operator was typed in and do the mathematical operation normally like num1+num2.
This is beyond the homework task we were set but what I'm trying to do now is replace the operator with a variable for example: "num1 + num2" would become "num1 variable num2" where variable equals "+" etc.
Is there a way to do this in Java?
Thanks in advance
Since you are interested in going beyond the scope of the training material, and assuming you've learned about interfaces already, I believe what you are looking for is a binary expression tree (that wikipedia article actually explains it good).
Basically, you create an interface Expression with a double compute() method. There will be two types of implementing classes:
Operand: Constant and Variable.
Operator: Plus, Minus, Multiply, Divide. Each will have two Expression fields: left and right.
Your text expression is then parsed into the expression tree:
// input: "num1 + num2 * 3"
// result expression tree will be built by parser using:
Expression a = new Variable("num1");
Expression b = new Variable("num2");
Expression c = new Constant(3);
Expression d = new Multiply(b, c);
Expression e = new Plus(a, d);
Map<String, Double> variables = /*defined elsewhere*/;
double result = e.compute(variables);
Your new assignment, should you choose to accept it, will be to write the expression classes and a parser to build the expression tree from a text expression.
Hope this will encourage you to go way beyond the training material, having some fun while playing.
First you can use a switch on String rather than if-then-else chain. Another way is to build a static final Map (E.g. HashMap) from String to Function. The strings are the operators. The Functions do the operation. In Java 8 you can give the functions as lambdas. I only have access through a phone right now so can't show code. Your question will be much better received if you add code showing what you mean.
This question already has answers here:
How to format strings in Java
(10 answers)
Closed 5 years ago.
Is there a more elegant way of doing this in Java?
String value1 = "Testing";
String test = "text goes here " + value1 + " more text";
Is it possible to put the variable directly in the string and have its value evaluated?
String test = String.format("test goes here %s more text", "Testing");
is the closest thing that you could write in Java
A more elegant way might be:
String value = "Testing";
String template = "text goes here %s more text";
String result = String.format(template, value);
Or alternatively using MessageFormat:
String template = "text goes here {0} more text";
String result = MessageFormat.format(template, value);
Note, if you're doing this for logging, then you can avoid the cost of performing this when the log line would be below the threshold. For example with SLFJ:
The following two lines will yield the exact same output. However, the second form will outperform the first form by a factor of at least 30, in case of a disabled logging statement.
logger.debug("The new entry is "+entry+".");
logger.debug("The new entry is {}.", entry);
Rythm a java template engine now released with an new feature called String interpolation mode which allows you do something like:
String result = Rythm.render("Hello #who!", "world");
The above case shows you can pass argument to template by position. Rythm also allows you to pass arguments by name:
Map<String, Object> args = new HashMap<String, Object>();
args.put("title", "Mr.");
args.put("name", "John");
String result = Rythm.render("Hello #title #name", args);
Links:
Check the full featured demonstration
read a brief introduction to Rythm
download the latest package or
fork it
It may be done by some template-libaries. But beware, Strings are immutable in Java. So in every case at some low level the concatenation will be done.
You'll always have to use some form of concatenation for this (assuming value1 isn't a constant like you show here).
The way you've written it will implicitly construct a StringBuilder and use it to concatenate the strings. Another method is String.format(String, Object...)1, which is analogous to sprintf from C. But even with format(), you can't avoid concatenation.
1 Yes, I know the anchor link is broken.
What you want is called String interpolation. It is not possible in Java, although JRuby, Groovy and probably other JVM languages do that.
Edit: as for elegance, you can use a StringBuffer or check the other poster's solution. But at the low level, this will always be concatenation, as the other posters said.
You can use this free library. It gives you sprintf like functionality. Or use String.format static method provided you use Java 5 or newer.
Why do you think string concatenation isn't elegant?
If all you are doing is simple concatenation, I'd argue that code readability is more important and I'd leave it like you have it. It's more readable than using a StringBuilder.
Performance won't be the problem that most people think it is.
Read this from CodingHorror
I would use a StringBuffer.. it's a common practise when you are dealing with strings. It may seem a bit when you see it for the first time, but you'll get quickly used to it..
String test = new StringBuffer("text goes here ").append(value1).append(" more text").toString();
Strings are immutable thus a new instance is created after every concatenation. This can cause performance issues when used in loops.
StringBuffer is mutable version of String - that means you can create one, modify it as you want and you have still only one instance. When desired you can get a String representation of the StringBuffer by calling it's toString() method.
The problem is not if this is an elegant way or not. The idea behind using a template system may be that you put your template in a normal text file and don't have to change java code if you change your message (or think about i18ln).
Can anyone recommend a framework for templating/formatting messages in a standalone application along the lines of the JSP EL (Expression Language)?
I would expect to be able to instantiate a an object of some sort, give it a template along the lines of
Dear ${customer.firstName}. You order will be dispatched on ${order.estimatedDispatchDate}
provide it with a context which would include a value dictionary of parameter objects (in this case an object of type Customer with a name 'customer', say, and an object of type Order with a name 'order').
I know there are many template frameworks out there - many of which work outside the web application context, but I do not see this as a big heavyweight templating framework. Just a better version of the basic Message Format functionality Java already provides
For example, I can accomplish the above with java.text.MessageFormat by using a template (or a 'pattern' as they call it) such as
Dear {0}. You order will be dispatched on {1,date,EEE dd MMM yyyy}
and I can pass it an Object array, in my calling Java program
new Object[] { customer.getFirstName(), order.getEstimatedDispatchDate() };
However, in this usage, the code and the pattern are intimately linked. While I could put the pattern in a resource properties file, the code and the pattern need to know intimate details about each other. With an EL-like system, the contract between the code and the pattern would be at a much higher level (e.g. customer and order, rather then customer.firstName and order.estimatedDispatchDate), making it easier to change the structure, order and contents of the message without changing any code.
You can just use the Universal Expression Language itself. You need an implementation (but there are a few to choose from). After that, you need to implement three classes: ELResolver, FunctionMapper and VariableMapper.
This blog post describes how to do it: Java: using EL outside J2EE.
StringTemplate is a more lightweight alternative to Velocity and Freemarker.
I would recommend looking into Apache Velocity. It is quite simple and lightweight.
We are currently using it for our e-mail templates, and it works very well.
You can use Casper very similar to jsp and easy to use : Casper
The idea of using EL itself outside of Java EE was advocated by Ed Burns and discussed on The Server Side. Tomcats implementation ships in a separate JAR but I don't know if it can be used outside the server.
I would go for the Spring Expression language:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/expressions.html
A few examples which demonstrate the power (the first two are from the documentation):
int year = (Integer) parser.parseExpression("Birthdate.Year + 1900").getValue(context);
String city = (String) parser.parseExpression("placeOfBirth.City").getValue(context);
// weekday is a String, e.g. "Mon", time is an int, e.g. 1400 or 900
{"Thu", "Fri"}.contains(weekday) and time matches '\d{4}'
Expressions can also use object properties:
public class Data {
private String name; // getter and setter omitted
}
Data data = new Data();
data.setName("John Doe");
ExpressionParser p = new SpelExpressionParser();
Expression e = p.parseExpression("name == 'John Doe'");
Boolean r = (Boolean) e.getValue(data); // will return true
e = p.parseExpression("Hello " + name + ", how are you ?");
String text = e.getValue(data, String.class); // text will be "Hello John Doe, how are you ?"
You might want to look at OGNL which is the kind of library you are after. OGNL can be reasonably powerful, and is the expression language used in the WebWork web framework.
Re: Jasper and Juel being built for 1.5: And then I discovered RetroTranslator (http://retrotranslator.sourceforge.net/). Once retrotranslated, EL and Jasper works like a charm
Freemarker would do exactly what you need. This is a template engine with a syntax very similar to JSP :
http://freemarker.org/
AAh. Whereas with MessageFormat, I can do
Dear {0}. Your order will be dispatched on {1,date,EEE dd MMM yyyy}
where parameter #1 is a Date object and it gets formatted according to the pattern, there is no equivalent in EL.
In JSP, I would have used, perhaps, a format tag. In this standalone example, I am going to have to format the Date as a String in my code prior to evaluating the expression.