Java: Understanding a Recursive Descent Parser Implementation - java

Let's say we have a simple grammar:
Program ::= Expression
Expression ::= Number
::= - ( Expression , Expression )
With this expression: -(-(8,3)4)
Returning 1.
My token stream(I splice parens and commas out) looks like this
(MINUS -)
(MINUS -)
(INTEGER 8)
(INTEGER 3)
(INTEGER 4)
So the AST would look like so
. . -
. - . 4
8..3
My question is, regarding the recursive nature of the grammar. How would a java example work given the difference expression has 2 evaluated expressions.
I've tried passing in expressions to a class constructor like so:
public class DiffExp implements LetLangExp {
LetLangExp left, right;
public DiffExp(LetLangExp l, LetLangExp r) {
left = l;
right = r;
eval();
}
}
This works for just a difference expression of -(number,number) but recursively it doesn't, because I can't seem to wrap head around the recursive nature of parsing it seems. I'm stuck on this example and i've looked online but i can't seem to equivocate this type of grammar to anything i've seen.
Essentially how do I implement a Difference Expression that is handled recursively that can take a difference expression as an operand and calculate that accordingly?
Edit: Per Markspace's request, i'm attempting to build a node structure for the parse tree. Here is the class I have right now.
class ExprNode{
String c;
static String operator;
static ExprNode operand1;
static ExprNode operand2;
public ExprNode(String num){
c = num;
operand1 = operand2 = null;
}
public static void Expr(String op, ExprNode e1, ExprNode e2){
operator = op;
operand1 = e1;
operand2 = e2;
}
}

Looks good but you'll want to separate tree building and evaluation:
public class DiffExp implements LetLangExp {
LetLangExp left, right;
public DiffExp(LetLangExp l, LetLangExp r) {
left = l;
right = r;
}
public double eval() {
return left.eval() - right.eval();
}
}
p.s. Parsing should be roughly as follows:
LetLangExpr parseProgram(LinkedList<String> tokens) {
return parseExpression(tokens);
}
LetLangExpr parseExpression(LinkedList<String> tokens) {
if ("-".equals(tokenStream.peekFirst())) {
return parseDiff(tokens);
} else {
return parseNumber(tokens);
}
}
LetLangExpr parseDiff(LinkedList<String> tokens) {
tokens.pollFirst(); // Consume "-"
LetLangExpr left = parseExpression(tokens);
LetLangExpr right = parseExpression(tokens);
return new DiffExpr(left, right);
}
LetLangExpr parseNumber(LinkedList<String> tokens) {
String numberStr = tokens.pollFirs();
double number = Double.parseDouble(numberStr);
return new NumberExpr(number);
}

You should create methods for each rule from the grammar, like:
parseProgram(String program) {
return parseExpression(program)
}
parseExpression(String expression) {
if ( isNumber(expression) ) {
return parseNumber(expression);
} else
if ( isSignedExpression(expression) ) {
String left = getLeftExpression(expression);
String right = getRightExpression(expression);
return parseExpression(left) - parseExpression(right);
}
}
parseNumber(String number) {
parsedNumber = ...
return parsedNumber;
}

Related

How to calculate value of math expression and check user answer?

Any help or advice would be greatly appreciated. I'm dooing a simple game which generates ten different, random questions. The questions can be composed from 2, 3 or 4 integers.Something like this: 552 − 4 − 101, 102 / 3 / 3, 589 − 281, 123 + 56 + 2.
The question will be displayed in a textview and then the user can take a guess, entering values into an edittext and then upon clicking a key on a custom keypad, it will check the answer, and then display the next question until it reaches 10 questions. I have a problem with imputing the answer from the code i have. No matter what i do here i cant input the answer to the randomly generated expression.
public enum Operator {
PLUS("+"), MINUS("-"), MULTIPLIER("*"), DIVIDER("/");
private String displayValue;
private Operator(String displayValue) {
this.displayValue = displayValue;
}
public String getDisplayValue() {
return displayValue;
}}
public class Question{
private List<QuestionElement> questionElements;
public Question(int sizeOfQuestionElemets) {
questionElements = new ArrayList<QuestionElement>(sizeOfQuestionElemets);
}
public void addElement(QuestionElement questionElement) {
questionElements.add(questionElement);
}
public List<QuestionElement> getElements() {
return questionElements;
}
public int size() {
return questionElements.size();
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (QuestionElement questionElement : questionElements) {
sb.append(questionElement);
}
return sb.toString().trim();
}
}
public class QuestionElement {
private int value;
private Operator operator;
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public Operator getOperator() {
return operator;
}
public void setOperator(Operator operator) {
this.operator = operator;
}
#Override
public String toString() {
return value + (operator == null ? "" : " " + operator.getDisplayValue()) + " ";
}
}
public class RandomQuestions {
static QuestionElement q = new QuestionElement();
private static final int NUMBER_OF_QUESTIONS = 10;
private static final int MIN_QUESTION_ELEMENTS = 2;
private static final int MAX_QUESTION_ELEMENTS = 2;
private static final int MIN_QUESTION_ELEMENT_VALUE = 1;
private static final int MAX_QUESTION_ELEMENT_VALUE = 20;
private final Random randomGenerator = new Random();
public List<Question> getGeneratedRandomQuestions() {
List<Question> randomQuestions = new ArrayList<>(NUMBER_OF_QUESTIONS);
int randomQuestionElementsCapacity = getRandomQuestionElementsCapacity();
Question question = new Question(randomQuestionElementsCapacity);
for (int j = 0; j < randomQuestionElementsCapacity; j++) {
boolean isLastIteration = j + 1 == randomQuestionElementsCapacity;
QuestionElement questionElement = new QuestionElement();
questionElement.setValue(getRandomQuestionElementValue());
questionElement.setOperator(isLastIteration ? null
: Operator.values()[randomGenerator.nextInt(Operator.values().length)]);
question.addElement(questionElement);
}
randomQuestions.add(question);
return randomQuestions;
}
private int getRandomQuestionElementsCapacity() {
return getRandomIntegerFromRange(MIN_QUESTION_ELEMENTS, MAX_QUESTION_ELEMENTS);
}
private int getRandomQuestionElementValue() {
return getRandomIntegerFromRange(MIN_QUESTION_ELEMENT_VALUE, MAX_QUESTION_ELEMENT_VALUE);
}
private int getRandomIntegerFromRange(int min, int max) {
return randomGenerator.nextInt(max - min + 1) + min;
}
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
RandomQuestions questionGenerator = new RandomQuestions();
List<Question> randomQuestions = questionGenerator.getGeneratedRandomQuestions();
for (Question question : randomQuestions) {
System.out.println(""+ question+"=?");
int answer = input.nextInt();
if (answer == q.getValue()) {
System.out.println("CORRECT");
}else{
System.err.println("STILL NOT WORKING");
}
}
}
}
In your main() you are printing question, reading an answer from the user and then comparing the answer to q.getValue(). q is a question element that is not related to question and always has value 0. So the trick is to answer 0 no matter what the question is, then the program will print CORRECT. :-)
I haven’t found anywhere in your code where you are calculating the correct value of the math expression. This would probably be a good first step towards checking whether the user has indeed entered the correct result.
Calculating the correct result is not really trivial if we insist on taking operator precedence into account. 4 + 3 * 2 should be 10 (not 14). I believe that reading about the Shunting-yard algorithm should get you some of the way. It’s an algorithm for parsing a math expression, which is only the first step towards calculating its value, but still a first step.
I suggest that the object-oriented approach will be that the Question object knows how to check an answer. Here is an implementation of the algorithm, simplified to the four operators, but extended to actually do the calculation:
public boolean checkAnswer(int answer) {
// calculate correct answer
// use shunting yard algorithm
Deque<Integer> outputQueue = new ArrayDeque<>();
Deque<Operator> operatorStack = new ArrayDeque<>();
for (QuestionElement element : questionElements) {
outputQueue.push(element.getValue());
Operator op = element.getOperator();
if (op != null) {
while (!operatorStack.isEmpty() && op.getPrecedence() <= operatorStack.peek().getPrecedence()) {
int operand2 = outputQueue.pop();
int operand1 = outputQueue.pop();
outputQueue.push(operatorStack.pop().apply(operand1, operand2));
}
operatorStack.push(op);
}
}
while (!operatorStack.isEmpty()) {
int operand2 = outputQueue.pop();
int operand1 = outputQueue.pop();
outputQueue.push(operatorStack.pop().apply(operand1, operand2));
}
int result = outputQueue.pop();
assert outputQueue.isEmpty();
return answer == result;
}
You notice that I have put some new demands on your Operator enum too. It has a precedence. And the + operator must know how to do addition (through its apply method), and similarly for the other operators:
PLUS("+", 1) {
#Override
public int apply(int operand1, int operand2) {
return operand1 + operand2;
}
},
// etc.
public abstract int apply(int operand1, int operand2);
and so on. 1 is the precedence; * and / have higher precedence, for example 2.
Now in main() you just need to write:
if (question.checkAnswer(answer)) {
If you decide to explain to the user that strict left-to-right evaluation is applied, it’s getting somewhat simpler:
public boolean checkAnswer(int answer) {
// calculate correct answer
// do left to right calculation
int result = questionElements.get(0).getValue();
for (int elementIndex = 1; elementIndex < questionElements.size(); elementIndex++) {
Operator op = questionElements.get(elementIndex - 1).getOperator();
result = op.apply(result, questionElements.get(elementIndex).getValue());
}
return answer == result;
}
The operators still need to have the apply method, but they no longer need the precedence.

Binary Search Trees : how can I compare variable's values of its elements?

So I have a BST and its elements are type TreeNode. Each TreeNode object includes a WordFreq object which consists of a String variable called word, and an integer variable called freq. The elements are words that my program reads from a file, so the variable "word" is that String, and variable freq represent the frequency that the word appears in the text. So what i want to do is go through the whole BST and find the TreeNode with the max frequency(max freq). I tried many ways, but it doesnt seem to work. The words are sorted on the tree alphabetically, NOT sorted by frequency. Here is my method:
public WordFreq getMaximumFrequency() {
return getMaximumFrequencyR(head, 1);
}
public WordFreq getMaximumFrequencyR(TreeNode h, int i) {
WordFreq temp = h.getWordFreq();
if (h.getWordFreq().getFreq() > getMeanFrequency()) { //line 3
if (h.l != null) {
if (h.getWordFreq().getFreq() >= i){
i = h.getWordFreq().getFreq();
temp = h.getWordFreq();
getMaximumFrequencyR(h.l, i);
}
}
if (h.r != null) {
if (h.getWordFreq().getFreq() >= i){
i = h.getWordFreq().getFreq();
temp = h.getWordFreq();
getMaximumFrequencyR(h.r, i);
}
}
}
else {
if (h.l != null) {
getMaximumFrequencyR(h.l, i);
}
if (h.r != null) {
getMaximumFrequencyR(h.r, i);
}
}
return temp;
}
getMeanFrequency() is a method that returns average frequency. The comparison on line 3 makes sense because it is required (for my assignment) that when a word has bigger frequency than average frequency of the tree, to be inserted at the root. That means that the maximum frequency I am looking for cannot be somewhere at the bottom of the tree.
(Language is Java)
Do you have any idea how I could make this work?
here are some helpfull method info to better comprehend my code:
class TreeNode:
public class TreeNode {
private WordFreq wf;
private TreeNode l, r;
private int N;
private TreeNode head;
public TreeNode() {
head = null;
l = null;
r = null;
}
public TreeNode(WordFreq wf) {
this.wf =wf;
l = null;
r = null;
N = 0;
}
public void incrSubtree(TreeNode tn) {
tn.N++;
}
public void decrSubtree(TreeNode tn) {
tn.N--;
}
public WordFreq getWordFreq() {
return wf;
}
}
class WordFreq:
public class WordFreq {
private String word;
private int freq;
public WordFreq(String word) {
this.word = word;
freq=1;
}
public String key() {
return this.word;
}
public void freqIncrease(WordFreq w) {
w.freq++;
}
public String toString() {
return "The word " + key() + " has frequency " + getFreq() + ".";
}
public int getFreq() {
return freq;
}
}
The pseudo-code for the algorithm you want is:
maxFrequency(NULL) = 0
maxFrequency(Node) = max(frequency(Node.value),maxFrequency(Node.right),maxFrequency(Node.Left));
It should not be hard to convert this pseudo-code to java.
Note that this does not take advantage of the fact that a node with above average frequency is inserted at the root. I do not think that it is easy to implement an algorithm that does.
If you need to do an exhaustive search of the tree (i.e. the highest frequency word could be anywhere) then this becomes relatively easy I believe.
However, first of all I suggest you don't set your l and r members to null in TreeNode. Instead I suggest you have a private static EMPTY TreeNode which overrides appropriate methods to play the part of null - such as returing a word frequency of 0. There are lots of reasons to do it this way but rather than list them I suggest you google it! I'm going to assume you've done that in the code below as it makes things a lot neater.
Add a TreeNode method:
public TreeNode maxFrequency() {
return Arrays.asList(this, l.maxFrequenc(), r.maxFrequency()).stream()
.max((tn1, tn2) -> tn1.wf.compareTo(tn2.wf))
.orElse(EMPTY);
}
Let me explain how this works in case you are not experienced with Java 8 streams. The Arrays.asList line creates a list of the current node and the maximum word frequency nodes from the left and right and then turns them into a stream. The max statement finds the one with the highest word frequency using a compareTo method (which you will need to add to the WordFrequency class). This returns a Optional<TreeNode> which could potentially be not present so the orElse statement returns EMPTY if there is no maximum.
Finally you'll need to override this maxFrequency method in the EMPTY TreeNode to just return this to avoid infinite recursion.

Java equality integer

I find it kind of confusing, I'm trying to solve this problem I found on the Internet as my programming exercise:
Implement a class with methods which takes one INTEGER parameter "initialValue" and returns following:
a. if initialValue is equal to 1 - return 2 (INTEGER)
b. if initialValue is equal to 2 - return 1 (INTEGER)
This is what I've done so far:
public static void main(String[] args) {
System.out.print(myMethod(1));
}
private static int myMethod(int initialValue) {
int n = 1;
if(initialValue == n) {
return 2;
} else {
return n;
}
}
But I guess this is a basic solution. Do you know any method variations other than this? Thanks.
little fancy solution would be doing XOR with 3
return initialValue ^ 3;
You might use the conditional operator ?: and something like
private static int myMethod(int initialValue) {
return initialValue == 1 ? 2 : 1;
}
The ternary operator is described in the Java Tutorials like
Another conditional operator is ?:, which can be thought of as shorthand for an if-then-else statement (discussed in the Control Flow Statements section of this lesson). This operator is also known as the ternary operator because it uses three operands. In the following example, this operator should be read as: "If someCondition is true, assign the value of value1 to result. Otherwise, assign the value of value2 to result."
I really hope that you plan on using this for learning only not to hand in as your own work. Your way works very well. However, you could also use the modulo operator (assuming of course that the only two inputs would be 1 and 2).
private static int myMethod(int initialValue) {
return initialValue % 2 + 1;
}
Best of luck with your CS aspirations!
public static void main(String[] args) {
int input;
// code for input value
System.out.print(myMethod(input));
}
private static int myMethod(int initialValue) {
int n = 1;
if(initialValue == n) {
return 2;
} else if(initialValue==2) {
return 1;
}
else {
return initialValue;
}
}
This might give better output if you insert values dynamically
It can also be done this way,
private static int myMethod(int initialValue) {
switch (initialValue){
case 1:
return 2;
case 2:
return 1;
default:
return 0;
}
}

print OO expression tree in java

I'm working on a java object oriented expression tree assignment where I need to be able to eval and print expression trees in prefix/infix/postfix formats. The assignment describes a class hierarchy with static type "Exp" and several unary and binary subclasses.
I've solved the eval part by having the unary and binary classes implement the eval() method (as dictated by the root type "Exp"), but need help with printing the expression. I've worked with this for days now and have gotten nowhere. All the help I've found online is about binary classes that has both operator and values fields (my assignment has these as two different classes). Please give me a kick in the right direction - I'll be most grateful :-)
Best wishes,
Rasmus
public interface Exp { double value(); }
public class Value implements Exp {
private double value;
public Value(double val) { this.value = val; }
public double value() { return this.value; }
}
public class Binary implements Exp {
private char op; private Exp right; private Exp left;
public Binary(char op, Exp left, Exp right) {
this.op = op; this.left = left; this.right = right;
}
}
public double value() { // sum up using recursion
switch(this.op) {
case '+': return this.left.value()+this.right.value();
case '-': return this.left.value()-this.right.value();
case '*': return this.left.value()*this.right.value();
case '/': return this.left.value()/this.right.value();
default: return Double.NaN;
}
}
}
public class Main { //calculating total ok - needs printing!
public static void Main(String[] args) {
Exp valLeft = new Value(10);
Exp valRight = new Value(5);
Exp bN1 = new Binary('+', valLeft, valRight);
Exp bN2 = new Binary('+', bN1, new Value(3));
System.out.println(bN2.value());
}
}
Here's how to do the infix. The prefix and postfix should be possible for you once you see how this one is done.
In the Exp interface, add:
String asInfix();
In the Binary class, add:
public final String asInfix() {
return "(" + left.asInfix() + " " + op + " " + right.asInfix() + ")";
}
In the Value class, add:
public final String asInfix() {
return "" + value;
}
Now you can do System.out.println(bN2.asInfix()); to display ((10.0 + 5.0) + 3.0).
Approach it in same manner. Override toString so that it calls it recursively for left and right in case of Binary, and returns the value for Value nodes.

Good way to encapsulate Integer.parseInt()

I have a project in which we often use Integer.parseInt() to convert a String to an int. When something goes wrong (for example, the String is not a number but the letter a, or whatever) this method will throw an exception. However, if I have to handle exceptions in my code everywhere, this starts to look very ugly very quickly. I would like to put this in a method, however, I have no clue how to return a clean value in order to show that the conversion went wrong.
In C++ I could have created a method that accepted a pointer to an int and let the method itself return true or false. However, as far as I know, this is not possible in Java. I could also create an object that contains a true/false variable and the converted value, but this does not seem ideal either. The same thing goes for a global value, and this might give me some trouble with multithreading.
So is there a clean way to do this?
You could return an Integer instead of an int, returning null on parse failure.
It's a shame Java doesn't provide a way of doing this without there being an exception thrown internally though - you can hide the exception (by catching it and returning null), but it could still be a performance issue if you're parsing hundreds of thousands of bits of user-provided data.
EDIT: Code for such a method:
public static Integer tryParse(String text) {
try {
return Integer.parseInt(text);
} catch (NumberFormatException e) {
return null;
}
}
Note that I'm not sure off the top of my head what this will do if text is null. You should consider that - if it represents a bug (i.e. your code may well pass an invalid value, but should never pass null) then throwing an exception is appropriate; if it doesn't represent a bug then you should probably just return null as you would for any other invalid value.
Originally this answer used the new Integer(String) constructor; it now uses Integer.parseInt and a boxing operation; in this way small values will end up being boxed to cached Integer objects, making it more efficient in those situations.
What behaviour do you expect when it's not a number?
If, for example, you often have a default value to use when the input is not a number, then a method such as this could be useful:
public static int parseWithDefault(String number, int defaultVal) {
try {
return Integer.parseInt(number);
} catch (NumberFormatException e) {
return defaultVal;
}
}
Similar methods can be written for different default behaviour when the input can't be parsed.
In some cases you should handle parsing errors as fail-fast situations, but in others cases, such as application configuration, I prefer to handle missing input with default values using Apache Commons Lang 3 NumberUtils.
int port = NumberUtils.toInt(properties.getProperty("port"), 8080);
To avoid handling exceptions use a regular expression to make sure you have all digits first:
//Checking for Regular expression that matches digits
if(value.matches("\\d+")) {
Integer.parseInt(value);
}
There is Ints.tryParse() in Guava. It doesn't throw exception on non-numeric string, however it does throw exception on null string.
After reading the answers to the question I think encapsulating or wrapping the parseInt method is not necessary, maybe even not a good idea.
You could return 'null' as Jon suggested, but that's more or less replacing a try/catch construct by a null-check. There's just a slight difference on the behaviour if you 'forget' error handling: if you don't catch the exception, there's no assignment and the left hand side variable keeps it old value. If you don't test for null, you'll probably get hit by the JVM (NPE).
yawn's suggestion looks more elegant to me, because I do not like returning null to signal some errors or exceptional states. Now you have to check referential equality with a predefined object, that indicates a problem. But, as others argue, if again you 'forget' to check and a String is unparsable, the program continous with the wrapped int inside your 'ERROR' or 'NULL' object.
Nikolay's solution is even more object orientated and will work with parseXXX methods from other wrapper classes aswell. But in the end, he just replaced the NumberFormatException by an OperationNotSupported exception - again you need a try/catch to handle unparsable inputs.
So, its my conclusion to not encapsulate the plain parseInt method. I'd only encapsulate if I could add some (application depended) error handling as well.
May be you can use something like this:
public class Test {
public interface Option<T> {
T get();
T getOrElse(T def);
boolean hasValue();
}
final static class Some<T> implements Option<T> {
private final T value;
public Some(T value) {
this.value = value;
}
#Override
public T get() {
return value;
}
#Override
public T getOrElse(T def) {
return value;
}
#Override
public boolean hasValue() {
return true;
}
}
final static class None<T> implements Option<T> {
#Override
public T get() {
throw new UnsupportedOperationException();
}
#Override
public T getOrElse(T def) {
return def;
}
#Override
public boolean hasValue() {
return false;
}
}
public static Option<Integer> parseInt(String s) {
Option<Integer> result = new None<Integer>();
try {
Integer value = Integer.parseInt(s);
result = new Some<Integer>(value);
} catch (NumberFormatException e) {
}
return result;
}
}
You could also replicate the C++ behaviour that you want very simply
public static boolean parseInt(String str, int[] byRef) {
if(byRef==null) return false;
try {
byRef[0] = Integer.parseInt(prop);
return true;
} catch (NumberFormatException ex) {
return false;
}
}
You would use the method like so:
int[] byRef = new int[1];
boolean result = parseInt("123",byRef);
After that the variable result it's true if everything went allright and byRef[0] contains the parsed value.
Personally, I would stick to catching the exception.
I know that this is quite an old question, but I was looking for a modern solution to solve that issue.
I came up with the following solution:
public static OptionalInt tryParseInt(String string) {
try {
return OptionalInt.of(Integer.parseInt(string));
} catch (NumberFormatException e) {
return OptionalInt.empty();
}
}
Usage:
#Test
public void testTryParseIntPositive() {
// given
int expected = 5;
String value = "" + expected;
// when
OptionalInt optionalInt = tryParseInt(value);
// then
Assert.assertTrue(optionalInt.isPresent());
Assert.assertEquals(expected, optionalInt.getAsInt());
}
#Test
public void testTryParseIntNegative() {
// given
int expected = 5;
String value = "x" + expected;
// when
OptionalInt optionalInt = tryParseInt(value);
// then
Assert.assertTrue(optionalInt.isEmpty());
}
My Java is a little rusty, but let me see if I can point you in the right direction:
public class Converter {
public static Integer parseInt(String str) {
Integer n = null;
try {
n = new Integer(Integer.tryParse(str));
} catch (NumberFormatException ex) {
// leave n null, the string is invalid
}
return n;
}
}
If your return value is null, you have a bad value. Otherwise, you have a valid Integer.
The answer given by Jon Skeet is fine, but I don't like giving back a null Integer object. I find this confusing to use. Since Java 8 there is a better option (in my opinion), using the OptionalInt:
public static OptionalInt tryParse(String value) {
try {
return OptionalInt.of(Integer.parseInt(value));
} catch (NumberFormatException e) {
return OptionalInt.empty();
}
}
This makes it explicit that you have to handle the case where no value is available. I would prefer if this kind of function would be added to the java library in the future, but I don't know if that will ever happen.
What about forking the parseInt method?
It's easy, just copy-paste the contents to a new utility that returns Integer or Optional<Integer> and replace throws with returns. It seems there are no exceptions in the underlying code, but better check.
By skipping the whole exception handling stuff, you can save some time on invalid inputs. And the method is there since JDK 1.0, so it is not likely you will have to do much to keep it up-to-date.
If you're using Java 8 or up, you can use a library I just released: https://github.com/robtimus/try-parse. It has support for int, long and boolean that doesn't rely on catching exceptions. Unlike Guava's Ints.tryParse it returns OptionalInt / OptionalLong / Optional, much like in https://stackoverflow.com/a/38451745/1180351 but more efficient.
Maybe someone is looking for a more generic approach, since Java 8 there is the Package java.util.function that allows to define Supplier Functions. You could have a function that takes a supplier and a default value as follows:
public static <T> T tryGetOrDefault(Supplier<T> supplier, T defaultValue) {
try {
return supplier.get();
} catch (Exception e) {
return defaultValue;
}
}
With this function, you can execute any parsing method or even other methods that could throw an Exception while ensuring that no Exception can ever be thrown:
Integer i = tryGetOrDefault(() -> Integer.parseInt(stringValue), 0);
Long l = tryGetOrDefault(() -> Long.parseLong(stringValue), 0l);
Double d = tryGetOrDefault(() -> Double.parseDouble(stringValue), 0d);
I would suggest you consider a method like
IntegerUtilities.isValidInteger(String s)
which you then implement as you see fit. If you want the result carried back - perhaps because you use Integer.parseInt() anyway - you can use the array trick.
IntegerUtilities.isValidInteger(String s, int[] result)
where you set result[0] to the integer value found in the process.
This is somewhat similar to Nikolay's solution:
private static class Box<T> {
T me;
public Box() {}
public T get() { return me; }
public void set(T fromParse) { me = fromParse; }
}
private interface Parser<T> {
public void setExclusion(String regex);
public boolean isExcluded(String s);
public T parse(String s);
}
public static <T> boolean parser(Box<T> ref, Parser<T> p, String toParse) {
if (!p.isExcluded(toParse)) {
ref.set(p.parse(toParse));
return true;
} else return false;
}
public static void main(String args[]) {
Box<Integer> a = new Box<Integer>();
Parser<Integer> intParser = new Parser<Integer>() {
String myExclusion;
public void setExclusion(String regex) {
myExclusion = regex;
}
public boolean isExcluded(String s) {
return s.matches(myExclusion);
}
public Integer parse(String s) {
return new Integer(s);
}
};
intParser.setExclusion("\\D+");
if (parser(a,intParser,"123")) System.out.println(a.get());
if (!parser(a,intParser,"abc")) System.out.println("didn't parse "+a.get());
}
The main method demos the code. Another way to implement the Parser interface would obviously be to just set "\D+" from construction, and have the methods do nothing.
They way I handle this problem is recursively. For example when reading data from the console:
Java.util.Scanner keyboard = new Java.util.Scanner(System.in);
public int GetMyInt(){
int ret;
System.out.print("Give me an Int: ");
try{
ret = Integer.parseInt(keyboard.NextLine());
}
catch(Exception e){
System.out.println("\nThere was an error try again.\n");
ret = GetMyInt();
}
return ret;
}
To avoid an exception, you can use Java's Format.parseObject method. The code below is basically a simplified version of Apache Common's IntegerValidator class.
public static boolean tryParse(String s, int[] result)
{
NumberFormat format = NumberFormat.getIntegerInstance();
ParsePosition position = new ParsePosition(0);
Object parsedValue = format.parseObject(s, position);
if (position.getErrorIndex() > -1)
{
return false;
}
if (position.getIndex() < s.length())
{
return false;
}
result[0] = ((Long) parsedValue).intValue();
return true;
}
You can either use AtomicInteger or the int[] array trick depending upon your preference.
Here is my test that uses it -
int[] i = new int[1];
Assert.assertTrue(IntUtils.tryParse("123", i));
Assert.assertEquals(123, i[0]);
I was also having the same problem. This is a method I wrote to ask the user for an input and not accept the input unless its an integer. Please note that I am a beginner so if the code is not working as expected, blame my inexperience !
private int numberValue(String value, boolean val) throws IOException {
//prints the value passed by the code implementer
System.out.println(value);
//returns 0 is val is passed as false
Object num = 0;
while (val) {
num = br.readLine();
try {
Integer numVal = Integer.parseInt((String) num);
if (numVal instanceof Integer) {
val = false;
num = numVal;
}
} catch (Exception e) {
System.out.println("Error. Please input a valid number :-");
}
}
return ((Integer) num).intValue();
}
This is an answer to question 8391979, "Does java have a int.tryparse that doesn't throw an exception for bad data? [duplicate]" which is closed and linked to this question.
Edit 2016 08 17: Added ltrimZeroes methods and called them in tryParse(). Without leading zeroes in numberString may give false results (see comments in code). There is now also public static String ltrimZeroes(String numberString) method which works for positive and negative "numbers"(END Edit)
Below you find a rudimentary Wrapper (boxing) class for int with an highly speed optimized tryParse() method (similar as in C#) which parses the string itself and is a little bit faster than Integer.parseInt(String s) from Java:
public class IntBoxSimple {
// IntBoxSimple - Rudimentary class to implement a C#-like tryParse() method for int
// A full blown IntBox class implementation can be found in my Github project
// Copyright (c) 2016, Peter Sulzer, Fürth
// Program is published under the GNU General Public License (GPL) Version 1 or newer
protected int _n; // this "boxes" the int value
// BEGIN The following statements are only executed at the
// first instantiation of an IntBox (i. e. only once) or
// already compiled into the code at compile time:
public static final int MAX_INT_LEN =
String.valueOf(Integer.MAX_VALUE).length();
public static final int MIN_INT_LEN =
String.valueOf(Integer.MIN_VALUE).length();
public static final int MAX_INT_LASTDEC =
Integer.parseInt(String.valueOf(Integer.MAX_VALUE).substring(1));
public static final int MAX_INT_FIRSTDIGIT =
Integer.parseInt(String.valueOf(Integer.MAX_VALUE).substring(0, 1));
public static final int MIN_INT_LASTDEC =
-Integer.parseInt(String.valueOf(Integer.MIN_VALUE).substring(2));
public static final int MIN_INT_FIRSTDIGIT =
Integer.parseInt(String.valueOf(Integer.MIN_VALUE).substring(1,2));
// END The following statements...
// ltrimZeroes() methods added 2016 08 16 (are required by tryParse() methods)
public static String ltrimZeroes(String s) {
if (s.charAt(0) == '-')
return ltrimZeroesNegative(s);
else
return ltrimZeroesPositive(s);
}
protected static String ltrimZeroesNegative(String s) {
int i=1;
for ( ; s.charAt(i) == '0'; i++);
return ("-"+s.substring(i));
}
protected static String ltrimZeroesPositive(String s) {
int i=0;
for ( ; s.charAt(i) == '0'; i++);
return (s.substring(i));
}
public static boolean tryParse(String s,IntBoxSimple intBox) {
if (intBox == null)
// intBoxSimple=new IntBoxSimple(); // This doesn't work, as
// intBoxSimple itself is passed by value and cannot changed
// for the caller. I. e. "out"-arguments of C# cannot be simulated in Java.
return false; // so we simply return false
s=s.trim(); // leading and trailing whitespace is allowed for String s
int len=s.length();
int rslt=0, d, dfirst=0, i, j;
char c=s.charAt(0);
if (c == '-') {
if (len > MIN_INT_LEN) { // corrected (added) 2016 08 17
s = ltrimZeroesNegative(s);
len = s.length();
}
if (len >= MIN_INT_LEN) {
c = s.charAt(1);
if (!Character.isDigit(c))
return false;
dfirst = c-'0';
if (len > MIN_INT_LEN || dfirst > MIN_INT_FIRSTDIGIT)
return false;
}
for (i = len - 1, j = 1; i >= 2; --i, j *= 10) {
c = s.charAt(i);
if (!Character.isDigit(c))
return false;
rslt -= (c-'0')*j;
}
if (len < MIN_INT_LEN) {
c = s.charAt(i);
if (!Character.isDigit(c))
return false;
rslt -= (c-'0')*j;
} else {
if (dfirst >= MIN_INT_FIRSTDIGIT && rslt < MIN_INT_LASTDEC)
return false;
rslt -= dfirst * j;
}
} else {
if (len > MAX_INT_LEN) { // corrected (added) 2016 08 16
s = ltrimZeroesPositive(s);
len=s.length();
}
if (len >= MAX_INT_LEN) {
c = s.charAt(0);
if (!Character.isDigit(c))
return false;
dfirst = c-'0';
if (len > MAX_INT_LEN || dfirst > MAX_INT_FIRSTDIGIT)
return false;
}
for (i = len - 1, j = 1; i >= 1; --i, j *= 10) {
c = s.charAt(i);
if (!Character.isDigit(c))
return false;
rslt += (c-'0')*j;
}
if (len < MAX_INT_LEN) {
c = s.charAt(i);
if (!Character.isDigit(c))
return false;
rslt += (c-'0')*j;
}
if (dfirst >= MAX_INT_FIRSTDIGIT && rslt > MAX_INT_LASTDEC)
return false;
rslt += dfirst*j;
}
intBox._n=rslt;
return true;
}
// Get the value stored in an IntBoxSimple:
public int get_n() {
return _n;
}
public int v() { // alternative shorter version, v for "value"
return _n;
}
// Make objects of IntBoxSimple (needed as constructors are not public):
public static IntBoxSimple makeIntBoxSimple() {
return new IntBoxSimple();
}
public static IntBoxSimple makeIntBoxSimple(int integerNumber) {
return new IntBoxSimple(integerNumber);
}
// constructors are not public(!=:
protected IntBoxSimple() {} {
_n=0; // default value an IntBoxSimple holds
}
protected IntBoxSimple(int integerNumber) {
_n=integerNumber;
}
}
Test/example program for class IntBoxSimple:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class IntBoxSimpleTest {
public static void main (String args[]) {
IntBoxSimple ibs = IntBoxSimple.makeIntBoxSimple();
String in = null;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
do {
System.out.printf(
"Enter an integer number in the range %d to %d:%n",
Integer.MIN_VALUE, Integer.MAX_VALUE);
try { in = br.readLine(); } catch (IOException ex) {}
} while(! IntBoxSimple.tryParse(in, ibs));
System.out.printf("The number you have entered was: %d%n", ibs.v());
}
}
Try with regular expression and default parameters argument
public static int parseIntWithDefault(String str, int defaultInt) {
return str.matches("-?\\d+") ? Integer.parseInt(str) : defaultInt;
}
int testId = parseIntWithDefault("1001", 0);
System.out.print(testId); // 1001
int testId = parseIntWithDefault("test1001", 0);
System.out.print(testId); // 1001
int testId = parseIntWithDefault("-1001", 0);
System.out.print(testId); // -1001
int testId = parseIntWithDefault("test", 0);
System.out.print(testId); // 0
if you're using apache.commons.lang3 then by using NumberUtils:
int testId = NumberUtils.toInt("test", 0);
System.out.print(testId); // 0
I would like to throw in another proposal that works if one specifically requests integers: Simply use long and use Long.MIN_VALUE for error cases. This is similar to the approach that is used for chars in Reader where Reader.read() returns an integer in the range of a char or -1 if the reader is empty.
For Float and Double, NaN can be used in a similar way.
public static long parseInteger(String s) {
try {
return Integer.parseInt(s);
} catch (NumberFormatException e) {
return Long.MIN_VALUE;
}
}
// ...
long l = parseInteger("ABC");
if (l == Long.MIN_VALUE) {
// ... error
} else {
int i = (int) l;
}
Considering existing answers, I've copy-pasted and enhanced source code of Integer.parseInt to do the job, and my solution
does not use potentially slow try-catch (unlike Lang 3 NumberUtils),
does not use regexps which can't catch too big numbers,
avoids boxing (unlike Guava's Ints.tryParse()),
does not require any allocations (unlike int[], Box, OptionalInt),
accepts any CharSequence or a part of it instead of a whole String,
can use any radix which Integer.parseInt can, i.e. [2,36],
does not depend on any libraries.
The only downside is that there's no difference between toIntOfDefault("-1", -1) and toIntOrDefault("oops", -1).
public static int toIntOrDefault(CharSequence s, int def) {
return toIntOrDefault0(s, 0, s.length(), 10, def);
}
public static int toIntOrDefault(CharSequence s, int def, int radix) {
radixCheck(radix);
return toIntOrDefault0(s, 0, s.length(), radix, def);
}
public static int toIntOrDefault(CharSequence s, int start, int endExclusive, int def) {
boundsCheck(start, endExclusive, s.length());
return toIntOrDefault0(s, start, endExclusive, 10, def);
}
public static int toIntOrDefault(CharSequence s, int start, int endExclusive, int radix, int def) {
radixCheck(radix);
boundsCheck(start, endExclusive, s.length());
return toIntOrDefault0(s, start, endExclusive, radix, def);
}
private static int toIntOrDefault0(CharSequence s, int start, int endExclusive, int radix, int def) {
if (start == endExclusive) return def; // empty
boolean negative = false;
int limit = -Integer.MAX_VALUE;
char firstChar = s.charAt(start);
if (firstChar < '0') { // Possible leading "+" or "-"
if (firstChar == '-') {
negative = true;
limit = Integer.MIN_VALUE;
} else if (firstChar != '+') {
return def;
}
start++;
// Cannot have lone "+" or "-"
if (start == endExclusive) return def;
}
int multmin = limit / radix;
int result = 0;
while (start < endExclusive) {
// Accumulating negatively avoids surprises near MAX_VALUE
int digit = Character.digit(s.charAt(start++), radix);
if (digit < 0 || result < multmin) return def;
result *= radix;
if (result < limit + digit) return def;
result -= digit;
}
return negative ? result : -result;
}
private static void radixCheck(int radix) {
if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
throw new NumberFormatException(
"radix=" + radix + " ∉ [" + Character.MIN_RADIX + "," + Character.MAX_RADIX + "]");
}
private static void boundsCheck(int start, int endExclusive, int len) {
if (start < 0 || start > len || start > endExclusive)
throw new IndexOutOfBoundsException("start=" + start + " ∉ [0, min(" + len + ", " + endExclusive + ")]");
if (endExclusive > len)
throw new IndexOutOfBoundsException("endExclusive=" + endExclusive + " > s.length=" + len);
}
I've been using a helper class that contains a static Queue of parsed values, and I find it to look quite clean. This would be the helper class could look like:
public static class Parsing {
// Could optimise with specific queues for primitive types
// and also using a circular queue, instead of LinkedList
private static final Queue<Number> QUEUE = new LinkedList<Number>();
public static boolean parseInt(String value) {
// Could implement custom integer parsing here, which does not throw
try {
QUEUE.offer(Integer.parseInt(value));
return true;
}
catch (Throwable ignored) {
return false;
}
}
public static int getInt() {
return QUEUE.remove().intValue(); // user's fault if this throws :)
}
}
And then in code, you use it like this:
public Vector3 parseVector(String content) {
if (Parsing.parseInt(content)) {
return new Vector3(Parsing.getInt());
}
else {
String[] parts = content.split(",");
if (Parsing.parseInt(parts[0]) && Parsing.parseInt(parts[1]) && Parsing.parseInt(parts[2])) {
// the queue ensures these are in the same order they are parsed
return new Vector3(Parsing.getInt(), Parsing.getInt(), Parsing.getInt());
}
else {
throw new RuntimeException("Invalid Vector3");
}
}
}
The only problem with this, is that if you use multiple calls like i did above, but maybe the last one fails, then you'd have to roll back or clear the queue
Edit: You could remove the above problem and include some thread safely, by making the class non-static and, maybe for slightly cleaner code, make the class implement AutoCloseable so that you could do something like this:
public Vector3 parseVector(String content) {
try (Parsing parser = Parsing.of()) {
if (parser.parseInt(content)) {
return new Vector3(parser.getInt());
}
else {
String[] parts = content.split(",");
if (parser.parseInt(parts[0]) && parser.parseInt(parts[1]) && parser.parseInt(parts[2])) {
// the queue ensures these are in the same order they are parsed
return new Vector3(parser.getInt(), parser.getInt(), parser.getInt());
}
else {
throw new RuntimeException("Invalid Vector3");
}
}
}
}
You can use a Null-Object like so:
public class Convert {
#SuppressWarnings({"UnnecessaryBoxing"})
public static final Integer NULL = new Integer(0);
public static Integer convert(String integer) {
try {
return Integer.valueOf(integer);
} catch (NumberFormatException e) {
return NULL;
}
}
public static void main(String[] args) {
Integer a = convert("123");
System.out.println("a.equals(123) = " + a.equals(123));
System.out.println("a == NULL " + (a == NULL));
Integer b = convert("onetwothree");
System.out.println("b.equals(123) = " + b.equals(123));
System.out.println("b == NULL " + (b == NULL));
Integer c = convert("0");
System.out.println("equals(0) = " + c.equals(0));
System.out.println("c == NULL " + (c == NULL));
}
}
The result of main in this example is:
a.equals(123) = true
a == NULL false
b.equals(123) = false
b == NULL true
c.equals(0) = true
c == NULL false
This way you can always test for failed conversion but still work with the results as Integer instances. You might also want to tweak the number NULL represents (≠ 0).
You could roll your own, but it's just as easy to use commons lang's StringUtils.isNumeric() method. It uses Character.isDigit() to iterate over each character in the String.
You shouldn't use Exceptions to validate your values.
For single character there is a simple solution:
Character.isDigit()
For longer values it's better to use some utils. NumberUtils provided by Apache would work perfectly here:
NumberUtils.isNumber()
Please check https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/math/NumberUtils.html

Categories

Resources