Evaluate String as a condition Java - java

I have to retrieve a set of column values from D/B and check it as a condition.
For example, I will have strings like "value > 2", "4 < value < 6" in a D/B column. (value is the one which is compared all the time). I will have a variable value declared in my code and I should evaluate this condition.
int value = getValue();
if (value > 2) //(the string retrieved from the D/B)
doSomething();
How can I do this?? Any help is muceh appreciated. Thanks.

Here is an example using the standard (Java 1.6+) scripting library:
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
public class Test {
public static void main(String[] args) throws Exception {
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("JavaScript");
engine.eval("value = 10");
Boolean greaterThan5 = (Boolean) engine.eval("value > 5");
Boolean lessThan5 = (Boolean) engine.eval("value < 5");
System.out.println("10 > 5? " + greaterThan5); // true
System.out.println("10 < 5? " + lessThan5); // false
}
}

You are basically evaluating a scripted expression. Depending what is allowed in that expression, you can get away with something very simple (regular expression identifying the groups) or very complex (embed a javascript engine?).
I'm assuming you're looking at the simple case, where the expression is:
[boundary0] [operator] "value" [operator] [boundary1]
Where one, but not both of the [boundary] [operator] groups might be omitted. (And if both are presents, operator should be the same)
I would use a regular expression for that with capturing groups.
Something like: (?:(\d+)\s*([<>])\s*)?value(?:\s*([<>])\s*(\d+))?
And then:
boundary1 = group(1); operator1 = group(2); operator2 = group(3); boundary2 = group(4)

It's not going to be trivial: you need a parser for the expression language used in your database. If it's some standard, well-specified language, then you might be able to find one on the Internet, but if it's an in-house thing, then you may need to write your own (perhaps using a parser generator like ANTLR.)
The javax.script package contains some tools for integrating external scripting engines like a Javascript interpreter. An alternative idea would be to bring in a scripting engine and feed the expressions to that.

You should try parsing the string inside the if statement by doing something like
if(parseMyString(getValue()))
doSomething();
In parseMyString can determine what you need to evaluate for the condition. If you don't know how to create a parser then take a look at: http://www.javapractices.com/topic/TopicAction.do?Id=87

This doesn't answer your question per se; it offers an alternate solution that may effect the same result.
Instead of storing a single database column with pseudocode that defines a condition, make a table in which the schema define types of conditions that must be satisifed and the values of those conditions. This simplifies programmatic evaluation of those conditions, but it may become complicated if you have a variety of types of conditions to evaluate.
For example, you might have a table that looks like the following.
CONDITION_ID | MINIMUM | MAXIMUM | IS_PRIME | ETC.
______________________________________________________
1 | 2 | NULL | NULL | ...
2 | 4 | 6 | NULL | ...
Those row entries, respectively map to the rules value > 2 and 6 > value > 4.
This confers a number of benefits over the approach you provide.
Improved performance and cleanliness
Your conditions can be evaluated at the database level, and can be used to filter queries
You needn't worry about handling scenarios in which your pseudocode syntax is broken

For evaluating the conditions with maximum flexibility use a scripting language designed for embedding, for instance MVEL can parse and evaluate simple conditional expression like the ones in the question.
Using MVEL has one huge advantage over using the Scripting engine in Java 1.6+ (in particular, with JavaScript): with MVEL you can compile the scripts to bytecode, making their evaluation much more efficient at runtime.

The latest version of java (Java 7) allows Switch Case statements on Strings, if there are not many possible variations you could just do this or similar :
int value = getValue();
switch(myString) {
case "value > 2" : if (value > 2) { doSomething();} break;
case "4 < value < 6" : if (value > 4 && value < 6) { doSomethingElse();} break;
default : doDefault();
}

A very good way of doing this apart from using Java 7 is using enums.
Declare enum as shown below
The above enum has a collection of constants whose values are set to the strings that you expect would be returned from the database. As you can use enums in switch cases the remaining code becomes easy
enum MyEnum
{
val1("value < 4"),val2("4<value<6");
private String value;
private MyEnum(String value)
{
this.value = value;
}
}
public static void chooseStrategy(MyEnum enumVal)
{
int value = getValue();
switch(enumVal)
{
case val1:
if(value > 2){}
break;
case val2:
if(4 < value && value < 6) {}
break;
default:
}
}
public static void main(String[] args)
{
String str = "4<value<6";
chooseStrategy(MyEnum.valueOf(str));
}
All you have to do is pass your string to the enum.valueof method and it will return the appropiate enum which is put in a switch case block to perform conditional operation . In the above code you can pass any string in place of what is passed in this example

Related

When would you use the conditional operator in java (? :) instead of the if else statement?

I have a piece of code that uses a conditional operator to compare the value of the variable x to 5:
(x >=5 ? x : -x)
What benefit is there to using a conditional operator over a regular if else statement?
Note that is ?: is an expression - it returns a value which must be consumed
z = (x >=5 ? x : -x)
The if construct in Java is not an expression (there are languages where it is) and does not return a value so in this sense they are not equivalent.
An example where they are equivalent is when the if options perform an assignment:
if("Cheese".equals(x)) {
type = "Dairy";
} else {
type = "Maybe not dairy";
}
this is the same as
type = "Cheese".equals(x) ? "Dairy" : "Maybe not dairy";
You can nest ?: to arbitrary depth but really shouldn't - it becomes quite difficult to read:
List<String> cheeses = Arrays.asList("Gouda", "Edam");
String x= "Gouda";
String type = cheeses.contains(x) ? "Gouda".equals(x) ? "Yummy Gouda" : "Cheese - but not Gouda" : "Maybe not dairy";
Ternary operator is not the equivalent of if-else in EVERY possible case. This is because both of possible results of using ternary operator are return values (e. g. simple printing to the console is not a return value so it can't be one of possible results in ternary operator).
Look, you can do it with if-else, but it's not possible with ternary operator:
if (x > 5) {
System.out.println("Statement is true");
else {
System.out.println("Statement is false");
}
You can't do it with ternary operator:
x > 5 ? System.out.println("Statement is true") : System.out.println("Statement is false");
When both of results of using ternary operator are considered as return values, they are then an equivalent of if-else.
Yes, it can be used, but off course in that case using -x doesn't make sense so it depends on what do you want to return when String is an input. You can do this:
("Cheese".equals(x) ? <some object of expected type X> : <some other object of expected type X>)
where X can be String on any other type. And remember to do "string".equals(x) instead of x.equals("string"). This prevents NullPointerException.
For primitive values you can use ==, but for objects you need to use equals method. There are some edge cases when you can use == on String, but they are not relevant to your case I guess and you can read about it outside of this topic.
PS: Some answers talk about if else statement, but that's not what question is about.
Can this be used like an if else on all accounts? For example, can you
compare strings with it?
I am pretty sure that by saying like an if else he means conditional operator which has if else like behaviour, not if else instruction itself.
Yes it can be used in Java; however note that x =="Cheese" isn't the proper way to compare strings in Java, you want something like "Cheese".equals(x).

How to construct specific Java regexp

I need to check a login name. It has to (it's political, not technical decision) have:
from 5 to 30 characters;
characters must be from group [a-zA-Z0-9*];
at least one character must be number;
it's not possible to have all characters just from numbers if login name has 5 characters but if it has 6 or more character, it can be constructed just from numbers.
I have regexp (?=[a-zA-Z0-9*]*[0-9])[a-zA-Z0-9*]{5,30} wich works for points 1-3, but can't imagine how to include check for point 4.
Use regex with negative look ahead assertion
(?!\d{5}$)(?=[a-zA-Z\d*]*\d)[a-zA-Z\d*]{5,30}
Regex explanation here.
It is always tempting to validate all aspects of a string using a single, pretty complicated regular expression. But keep in mind that this thing might be hard to extend, maintain in the future.
Meaning: depending on the rate of "changes" to your validation rules, there might be better designs. For example, one could envision something like:
interface NameValidator {
isValid(String name) throws InvalidNameException;
}
class LengthValidator implements NameValidator ...
class XyzValidator implements NameValidator ...
class NameValidation {
private final List validators = Arrays.toList(new LengthValidator(), ...
void isValid(String name) {
run all validators ...
This way, adding / changing one of your validation rules ... becomes much more straight forward ... than tampering a single regular expression, potentially breaking some other part of it.
Beyond that, you can even build different rule set; by combining different instances of NameValidation implementers; whilst avoiding code duplication .
As others have pointed out, you don’t have to do it with a single regex. Even if that’s possible, it will be obnoxiously complex and difficult for others to understand.
The simplest approach is the best:
boolean passwordValid = password.matches("[a-zA-Z0-9*]{5,30}")
&& password.matches(".*[0-9].*")
&& !password.matches("[0-9]{5}");
I'd like to propose a different approach: don't use a regex but check each character and collect password properties. That way you are able to implement more complex requirements later on, e.g. "it must have 3 out of 4".
Example:
String pw = "1a!cde";
Set<PwProperty> passwordProperties = new HashSet<>();
for( char c : pw.toCharArray() ) {
if( isDigit( c ) ) {
passwordProperties.add( PwProperty.DIGIT );
}
else if ( isSpecialChar( c ) ) {
passwordProperties.add( PwProperty.SPECIAL);
}
else if( isUpperCase( c ) ) {
passwordProperties.add( PwProperty.UPPER_CASE);
}
else if( isLowerCase( c ) ) {
passwordProperties.add( PwProperty.LOWER_CASE);
}
else {
passwordProperties.add( PwProperty.UNKNOWN );
}
}
Then you could check that like this (pseudo code):
if( !pw.length() in range ) {
display "password too short" or "password too long"
}
if( passwordProperties.contains( PwProperty.UNKNOWN ) {
display "unsupported characters used"
}
Set<PwProperty> setOf4 = { DIGIT, SPECIAL, LOWER_CASE, UPPER_CASE }
if( intersection( passwordProperties, setOf4 ).size() < 3 ) {
display "use at least 3 out of 4"
}
if( !passwordProperties.contains( DIGIT ) ) {
display "must contain digits"
}
display "password strength" being intersection( passwordProperties, setOfGoodProperties ).size()
etc.
This can then be expanded e.g. with properties like DIGIT_SEQUENCE which might be unwanted etc.
The main advantage is that you have more detailed information on the password rather than "it matches a certain regex or not" and you can use that information to guide the user.

BNF recursion in EpochX framework

Hopefully there are a few experts in the EpochX framework around here...I'm not sure that the user group is still active.
I am attempting to implement simple recursion within their represention of a BNF grammar and have fun into the following issue:
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: -9
at java.lang.String.substring(String.java:1911)
at org.epochx.epox.EpoxParser.parse(EpoxParser.java:235)
at org.epochx.epox.EpoxParser.parse(EpoxParser.java:254)
at org.epochx.tools.eval.EpoxInterpreter.eval(EpoxInterpreter.java:89)
at org.epochx.ge.model.epox.SAGE.getFitness(SAGE.java:266)
at org.epochx.ge.representation.GECandidateProgram.getFitness(GECandidateProgram.java:304)
at org.epochx.stats.StatField$7.getStatValue(StatField.java:97)
at org.epochx.stats.Stats.getStat(Stats.java:134)
at org.epochx.stats.StatField$8.getStatValue(StatField.java:117)
at org.epochx.stats.Stats.getStat(Stats.java:134)
at org.epochx.stats.Stats.getStats(Stats.java:162)
at org.epochx.stats.Stats.print(Stats.java:194)
at org.epochx.stats.Stats.print(Stats.java:178)
at org.epochx.ge.model.epox.Tester$1.onGenerationEnd(Tester.java:41)
at org.epochx.life.Life.fireGenerationEndEvent(Life.java:634)
at org.epochx.core.InitialisationManager.initialise(InitialisationManager.java:207)
at org.epochx.core.RunManager.run(RunManager.java:166)
at org.epochx.core.Model.run(Model.java:147)
at org.epochx.ge.model.GEModel.run(GEModel.java:82)
at org.epochx.ge.model.epox.Tester.main(Tester.java:55)
Java Result: 1
My simple grammar is structured as follows, where terminals are passed in separately to the evaluation function:
public static final String GRAMMAR_FRAGMENT = "<program> ::= <node>\n"
+ "<node> ::= <s_list>\n"
+ "<s_list> ::= <s> | <s> <s_list>\n"
+ "<s> ::= FUNCTION( <terminal> )\n"
+ "<terminal> ::= ";
Edit: Terminal creation -
// Generate the input sequences.
inputValues = BoolUtils.generateBoolSequences(4);
argNames = new String[4];
argNames[0] = "void";
argNames[1] = "bubbleSort";
argNames[2] = "int*";
argNames[3] = "numbers";
...
// Evaluate all possible inputValues.
for (final boolean[] vars: inputValues) {
// Convert to object array.
final Boolean[] objVars = ArrayUtils.toObject(vars);
Boolean result = null;
try {
interpreter.eval(program.getSourceCode(),
argNames, objVars);
score = (double)program.getParseTreeDepth();
} catch (final MalformedProgramException e) {
// Assign worst possible fitness and stop evaluating.
score = 0;
break;
}
}
The stacktrace shows that the problem is actually in the EpoxParser, this means that its not so much the grammar that is ill-formed, but rather that the programs that get generated cannot be parsed.
Because you're using the EpoxInterpreter, the programs that get generated get parsed as Epox programs. Epox is the name used to refer to the language that the tree representation of EpochX uses (a sort of corrupted form of Lisp which you can add your own literals/functions to). The parsing expects the S-Expression format, and tries to identify each function and terminal and it builds a tree made up of equivalent Node objects (see the org.epochx.epox.* packages). Then the tree can be evaluated to run the program.
But in Epox there's no built-in function called FUNCTION, nor any known literals 'void', 'bubbleSort', 'int*' or 'numbers'. So the parsing fails. So you need to add these constructs to the EpoxParser, so it knows how to parse them into nodes. You can do this with the declareFunction, declareLiteral and declareVariable methods (see the JavaDoc for the EpoxParser http://www.epochx.org/javadoc/1.4/).

Why does java require a double equals sign?

Why does java require a double equals sign (==) when comparing Integers in a if statement?
For example
if(x = 3.141)
System.out.println("x is equal to pi.");
is incorrect, it should be
if(x == 3.141)
System.out.println("x is equal to pi.");
I know that "==" is used to compare integers and "=" is used to set an integer value, but why in a if statement does this remain true?
Is it even allowed to assign a variable a value in an if statement (or initiate a new variable)?
Is there any reason anyone would ever want to assign a variable a new value inside an if statement (if so please provide an example)?
This seems like a question that should already have an answer, but I was unable to find one on here or using google, if this is a duplicate question please tell me and I will remove it immediately.
Wouldn't it be confusing if = sometimes did assignment, and sometimes comparison, depending in which context you used it?
That sounds like a bad idea, and would introduce errors.
Plus, the current syntax is compatible with C and C++, so a lot of people are familiar with it.
Is there any reason anyone would ever want to assine a variable a new value inside of an if statement (if so please provide an example)?
It's quite common in while loops:
int b;
while ((b=in.read()) != -1){
=
is used for assignment.
==
is used for comparison.
Is it even allowed to assign a variable a value in an if statement (or initiate a new variable)?
yes it is allowed.
Note what error message you get for if (x = 3.141); it is a type error (cannot convert from double to boolean).
The assignment's type is the type of its both sides; if the type of the assignment is boolean (if (x = true), or even if (x = a.equals(b))), then it is legal to write.
So since it is legal to assign a value to a boolean in the condition, you'd have to use == for comparison.
Is it even allowed to assine a variable a value in an if statement (or initiate a new variable)?
Yes. A common idiom for doing this is:
String line = null;
while ( (line = in.readLine()) != null ) {
// do work
}
In the loop, line is assigned a value and then compared to null. I can't think of an example with ints; it certainly wouldn't be clear there.
History of programming languages 101:
Fortran uses = for both.
Algol introduced := for assignment and used = for comparison. This was required to resolve a grammar ambiguity.
Pascal followed suit.
PL/1 did not.
I can't speak for B or BCPL but by the time we got C it was = for assignment and == for comparison, again to resolve a grammar ambiguity
C++ followed C
Java followed C++ in many respects including this one.
The grammar ambiguity arises because of allowing assignments in expressions. Contrary to your assertion, if (x = true) is legal in Java if x is of type boolean.
== is the identity comparator, which works for both objects and primitives. It answers the question "are the two things the same thing".
= is the assignment operator. It sets the value of the left side to the right side.
Things can turn buggy when using your example with booleans:
boolean b;
if (b = true) // This compiles, but is a bug, because it sets b, not tests it
While other types won't compile with this syntax, boolean and Boolean do, so that's why the following pattern is advised:
if (b)
you can absolutely assign a variable in an if statement. also, that's just the way it works: = always is assignment, and == is always comparison.
So..
= is assignment, and == is comparison, and it is always like this, no matter where they are used.
And assignment is different with "declaration". An assignment statement has its return value, while a declaration doesn't. So you can't write boolean a = false in the () of if statement, but you can write a = false when a has been declared before.
Not all assignments are legal. For example:
int index;
if (index = str.indexOf("something")) {
...
}
It's not legal, because String.indexOf(String) returns an int, while if requires a boolean.
Also, there is a huge difference between "legal" and "making sense".
int index;
if ((index = str.indexOf("something")) != -1) {
...
}
It is legal, as != operation returns a boolean, and it makes sense, as I do want to check if the str contains a substring "something";
However,
int index;
boolean flag;
if ( flag = ((index = str.indexOf("something")) != -1) ) {
...
}
is also legal, as the statement as last returns a boolean; but it DOESN'T make sense, because the != statement already returns a boolean.

Why is string comparison failing in my code?

I have an array in containing numbers that represent cable sizes (1, 1.5, 2.5, etc), stored as strings.
In my program, the array is loaded into a spinner, which is working fine.
However, when the item is selected and stored in a variable, I want to check what string was selected, and set another numerical variable to 2.5 so I can do a calculation later in the program.
I tried the following:
if (conductorSize = "1" ) {conCsa = 1;}
else if (conductorSize = "1.5") {conCsa = 1.5;}
conductorSize being the variable holding the selected string, and conCsa being the variable
set to a numerical variable for calculation.
The compiler says that I cannot convert a string to boolean. What's happening?
If you are doing string comparisons, use .equals()
Example taken from here:
String s = "something", t = "maybe something else";
if (s == t) // Legal, but usually WRONG.
if (s.equals(t)) // RIGHT <<<<<<<<<<<<< Use this.
if (s > t) // ILLEGAL
if (s.compareTo(t) > 0) // CORRECT>
As Ed S. points out you are using the assignment operator. However since you are comparing a String you need to use the equals method.
if ("1".equals(conductorSize)) {conCsa = 1;}
else if ("1.5".equals(conductorSize)) {conCsa = 1.5;}
Alternatively, you could just create a new float from your String:
float conCsa;
try {
conCsa = Float.parseFloat(conductorSize);
}catch(NumberFormatException e){
conCsa = 0.0f; //set to a default value
}
It looks like what you're trying to do might better be expressed in this way:
conCsa = Double.parseDouble(conductorSize);
In general you need to use the .equals() method.
If performance is extremely important and you are comparing against string literals, take a look at String.intern(). It'll allow you to do super-fast == comparisons and avoid a full character-by-character scan as in .equals().
Performance would have to be really, really important though, to justify such a non-standard approach.
When you have cable sizes which are constants, you need to use Enums , which will help you in reducing no of if condition comparisons.

Categories