Java Postfix char to String conversion - java

Using BlueJ to write the code and jUnit to test it out.
Trying to convert a infixToPostfix class I have from my lab class from using char to using strings. This would make it so instead of being limited to single input of say "ab+c-d*-" of char's, it would be able to read "a b + c - d * -"
It's working with a stack which is fairly new to me and I have no idea how exactly I'd go about this. The code I have so far is:
public class InfixToPostfix
{
private Stack operators = new Stack();
/**
* Constructor for objects of class InfixToPostfix
*/
public InfixToPostfix()
{
}
/**
* toPostfix
*/
public String toPostfix(String infix)
{
String [] tokens = new String[100];
int i;
int length = infix.length();
String operator;
String output = "";
for (i = 0; i < length; i++)
{
if (isOperator(tokens[i]))
if (operators.empty())
// 2. If the stack is empty, push the incoming operator onto the stack.
operators.push(tokens[i] + " ");
else
{
if (operatorLessPrecedence(tokens[i]))
// 3. If the incoming symbol has equal or lower precedence than the
// symbol on the top of the stack, pop the stack and print the top
// operator. Then test the incoming operator against the new top of stack.
// Push the incoming symbol onto the stack.
{
do
{
output = output + operators.pop();
}
while (!operators.empty() && operatorLessPrecedence(tokens[i]));
operators.push(tokens[i] + " ");
}
else
// 4. If the incoming symbol has higher precedence than the top of the stack,
// push it on the stack.
operators.push(tokens[i]);
}
else
// 1. Print operands as they arrive.
output = output + tokens[i] + " ";
}
while (!operators.empty())
{
// 5. At the end of the expression, pop and print all operators on the stack.
operator = (String)operators.pop();
output = output + operator + " ";
}
return output;
}
/**
* isOperator
*/
public boolean isOperator(String c)
{
if( c.equals("/") ||
c.equals("'") ||
c.equals("+") ||
c.equals("-"))
return true;
else
return false;
}
/**
* operatorLessPrecedence
* Compare operator with top of stack
* Assume association left to right
*/
public boolean operatorLessPrecedence(String o)
{
int operatorPrecedence = precedence(o);
int tosPrecedence = precedence((String)operators.peek());
return (operatorPrecedence <= tosPrecedence);
}
/**
* precedence
*/
public int precedence(String o)
{
switch (o)
{
case "+": return 1;
case "-": return 1;
case "*": return 2;
case "/": return 2;
}
return 5;
}
}
So when I test in jUnit using a assertEquals;
#Test
public void testAddSub()
{
InfixToPostfix test = new InfixToPostfix();
assertEquals("1 2 +", test.toPostfix("1 + 2"));
assertEquals("2 1 -", test.toPostfix("2 - 1"));
}
I get an exception method currently, before i changed the isOperator method from "==" which was used for testing char's to what I thought was correct, the .equals() method to test strings, I would only get null outputs..
I don't want a straight up code or what exactly I'm doing wrong, just a "forceful" nudge in the right direction or something I can look into. Thanks.

An array of objects holds a reference to the object. When you initialized the array, you just allocated the memory for 100 empty spots. You have to put some real Strings objects on it, otherwise NullPointerException 'll be your output.
So, in your line
String [] tokens = new String[100];
You have an array of 100 Strings references which values are null.
The correct way to compare String objects is using equals method.
Using == you'll test object references, equals tests the String value. So, don't change your method implementation, you are in the right path.
I don't recommend the use of Stack object. As you stated that Stack is a new thing for you and you are trying to improve, I would recommend that you take a look at this discussion if you have time available and get your own conclusion.
Why should I use Deque over Stack?.

Related

How to replace the overridden methods with a Recursive implementation

I want to use recursion in order to collapse the overridden add() methods in the code and allow the user to provide any number of terms.
I've made a couple of changes to my code, but I'm not getting the desired result.
Examples of user input and expected output.
Output (for input 3 + 4)
7.0
Output (for input 3 + 4 + 5)
12.0
The code I have:
import java.util.*;
public class Recursion {
public static void main(String args[]) {
Scanner input = new Scanner(System.in);
String exp = input.nextLine();
System.out.println(solver(exp.split(" ")));
}
public static double solver(String[] expression) {
double result = 0;
if (expression.length == 3) {
result = add(Double.parseDouble(expression[0]), Double.parseDouble(expression[2]));
}
else if (expression.length == 5) {
result = add(Double.parseDouble(expression[0]), Double.parseDouble(expression[2]),
Double.parseDouble(expression[4]));
}
else if (expression.length == 7) {
result = add(Double.parseDouble(expression[0]), Double.parseDouble(expression[2]),
Double.parseDouble(expression[4]), Double.parseDouble(expression[6]));
}
else if (expression.length == 9) {
result = add(Double.parseDouble(expression[0]), Double.parseDouble(expression[2]),
Double.parseDouble(expression[4]), Double.parseDouble(expression[6]),
Double.parseDouble(expression[8]));
}
else if (expression.length == 11) {
result = add(Double.parseDouble(expression[0]), Double.parseDouble(expression[2]),
Double.parseDouble(expression[4]), Double.parseDouble(expression[6]),
Double.parseDouble(expression[8]), Double.parseDouble(expression[10]));
}
return result;
}
public static double add(double a, double b) {return a + b;}
public static double add(double a, double b, double c) {return a + b + c;}
public static double add(double a, double b, double c, double d) {return a + b + c + d;}
public static double add(double a, double b, double c, double d, double e) {return a + b + c + d + e;}
public static double add(double a, double b, double c, double d, double e, double f) {return a + b + c + d + e + f;}
}
That's doable with recursion.
But before diving into recursive implementation, it's worth to find out how to solve this problem iteratively because it'll give you a better understanding of what the recursion does.
Firstly, I want to point out at issues with the code you've provided.
Your existing solution is brittle since it depends on the consistency of the user input, and it will fail because of the single additional white space or if a white space will be missing.
Another draw-back is that you have a lot of methods and with them, you are able to handle only a limited number of arguments in the given expression. Let's fix it.
Since your code is intended to perform the arithmetical addition, I think it'll be better to split the input on the plus symbol + and give a user a bit of freedom with white spaces.
For that, we need to pass the following regular expression into the split() method:
"\\s*\\+\\s*"
\s* - implies 0 or more white spaces;
\+ - plus symbol has a special meaning in regular expressions and needs to be escaped with a back-slash.
And since there's more than one arithmetical operation (and you also might want to implement others letter on). It's better to extract your the logic for splitting the user input into a separate method:
public static double add(String expression) {
return addIteratively(expression.split("\\s*\\+\\s*"));
}
expression.split() will return an array of numeric strings that will allow to substitute all your methods with a single method that expects a string array String[] or varargs String... expression (which will allow you to pass as an argument either an array of strings or arbitrary number of string values).
public static double addIteratively(String[] operands) {
double result = 0;
for (String next: operands) {
result += Double.parseDouble(next);
}
return result;
}
Now, when it's clear how to deal with this task iteratively (remember every problem and could be addressed using iteration is also eligible for recursion and vice versa) let's proceed with a quick recap on recursion.
Every recursive method consists of two parts:
Base case - that represents a simple edge-case (condition when recursion terminates) for which the outcome is known in advance.
Recursive case - a part of a solution where recursive calls are made and where the main logic resides.
To process the given array recursively, we can track the position in the array by passing it with each method call.
The base case will represent a situation when there's no more elements left in the array, i.e. current position is equal to the array's length. Since there's no element under the given position, the return is 0.
In the recursive case we need to parse the number under the current position and add the result of the recursive call with position incremented by 1 to it. That will give us the return value.
The recursive implementation might look that:
public static double addAsDouble(String[] operands, int pos) {
if (pos == operands.length) { // base case
return 0;
}
// recursive case
return Double.parseDouble(operands[pos]) + addAsDouble(operands, pos + 1);
}
Method responsible for splitting the user input.
public static double add(String expression) {
return addAsDouble(expression.split("\\s*\\+\\s*"), 0); // recursion starts at position 0
}
main() - here, you just need to call the add() providing a string inter by the user and bother of what is happening inside add. That makes code cleaner and easier to read.
public static void main(String args[]) {
Scanner input = new Scanner(System.in);
String exp = input.nextLine();
System.out.println(add(exp));
}
Output
3 + 4 +5
12.0
You are not passing the correct indexes to the various add methods. For example, if you want to add three numbers, you should do the following:
result = add(Double.parseDouble(expression[0]), Double.parseDouble(expression[1]), Double.parseDouble(expression[2]));

Android/Java using two dimensional array to create chatbot

public class ChatBot {
String[][] chatBot={
// standard greetings
{ "hi", "hello", "hey" }, { "hi user"},
// question greetings
{ "how are you" }, { "good"},
// default
{ "I did not understand. Please try something else" }, };
public ChatBot() {
}
public String checkAnswer(String message) {
byte response = 0;
int messageType = 0;
String x = null;
List temp;
int cblength = chatBot.length - 1;
while (response == 0 && messageType <= cblength) {
temp = Arrays.asList(chatBot[messageType]);
if (temp.contains(message)) {
response = 2;
x = chatBot[(messageType) + 1][0];
}
messageType = messageType + 2;
if (response == 1)
x = chatBot[chatBot.length - 1][0];
}
}
return x;
}
I created this simple chatbot to test my chat application. It uses a two dimensional String Array to save the possible inputs and outputs. The checkAnwer method receives the user input and is supposed to return the correct output. It uses a while loop to check the input fields and return the corresponding output, if the content of the field matches with the array. If the loop reaches the end of the array, it is supposed to return the default answer. The first group of inputs (hi/hello/hey) returns the right output(hi user), but every other input causes the while-loop to exceed the array length.
Edit
I removed the error in the Code, all inputs are now accepted, non valid inputs return null.
Edit2
I changed int cblength = chatBot.length - 1;
to
int cblength = chatBot.length;
and messageType = messageType + 2;
to
if ((messageType+2)>=cblength)
{
response=1;
}
else {
messageType = messageType + 2;
}
The code is now working properly.
If I'm understanding your code correctly, chatBot has a length of 5. On each full pass of the while loop, messageType is incrementing by 2. This means that on the second pass, messageType = 2. This means that on the following line :
x = chatBot[(messageType * 2) + 1][0];
We are looking for (2*2)+1 = 5 as an index. As the list is of length 5, the max index is 4, causing the IndexOutOfBoundsException.
There are two main ways I could see to fix this:
Reconsider whether you really need to repeat the same block of code twice in the while loop - this adds a bit of unneeded complexity, and reduces how often the while conditions are checked.
Update the while condition to check that any (messageType*2)+1 which will occur during the iteration will still be within the bounds of the array.

All possible distinct subsets of characters in a given string JAVA

As title says I need to do the following. But I somehow am getting the wrong answer, perhaps something with the loops is wrong?
And here's what I have coded so far, but it seems to be giving me the wrong results. Any ideas, help, tips, fixes?
import java.util.ArrayList;
public class pro1
{
private String lettersLeft;
private ArrayList<String> subsets;
public pro1(String input)
{
lettersLeft = input;
subsets = new ArrayList<String>();
}
public void createSubsets()
{
if(lettersLeft.length() == 1)
{
subsets.add(lettersLeft);
}
else
{
String removed = lettersLeft.substring(0,1);
lettersLeft = lettersLeft.substring(1);
createSubsets();
for (int i = 0; i <= lettersLeft.length(); i++)
{
String temp = removed + subsets.get(i);
subsets.add(temp);
}
subsets.add(removed);
}
}
public void showSubsets()
{
System.out.print(subsets);
}
}
My test class is here:
public class pro1
{
public static void main(String[] args)
{
pro1s = new pro1("abba");
s.createSubsets();
s.showSubsets();
}
}
Try
int numSubsets = (int)java.lang.Math.pow(2,toSubset.length());
for (int i=1;i<numSubsets;i++) {
String subset = "";
for (int j=0;j<toSubset.length();j++) {
if ((i&(1<<j))>0) {
subset = subset+toSubset.substring(j,j+1);
}
}
if (!subsets.contains(subset)) {
subsets.add(subset);
}
}
where toSubset is the string that you wish to subset (String toSubset="abba" in your example) and subsets is the ArrayList to contain the results.
To do this we actually iterate over the power set (the set of all subsets), which has size 2^A where A is the size of the original set (in this case the length of your string).
Each subset can be uniquely identified with a number from 0 to 2^A-1 where the value of the jth bit (0 indexed) indicates if that element is present or not with a 1 indicating presence and 0 indicating absence. Note that the number 0 represents the binary string 00...0 which corresponds to the empty set. Thus we start counting at 1 (your example did not show the empty set as a desired subset).
For each value we build a subset string by looking at each bit position and determining if it is a 1 or 0 using bitwise arithmetic. 1<<j is the integer with a 1 in the jth binary place and i&(i<<j) is the integer with 1's only in the places both integers have a 1 (thus is either 0 or 1 based on if i has a 1 in the jth binary digit). If i has a 1 in the jth binary digit, we append the jth element of the string.
Finally, as you asked for unique subsets, we check if we have already used that subset, if not, we add it to the ArrayList.
It is easy to get your head all turned around when working with recursion. Generally, I suspect your problem is that one of the strings you are storing on the way down the recursion rabbit hole for use on the way back up is a class member variable and that your recursive method is a method of that same class. Try making lettersLeft a local variable in the createSubsets() method. Something like:
public class Problem1
{
private String originalInput;
private ArrayList<String> subsets;
public Problem1(String input)
{
originalInput = input;
subsets = new ArrayList<String>();
}
// This is overloading, not recursion.
public void createSubsets()
{
createSubsets(originalInput);
}
public void createSubsets(String in)
{
if(in.length() == 1)
{
// this is the stopping condition, the bottom of the rabbit hole
subsets.add(in);
}
else
{
String removed = in.substring(0,1);
String lettersLeft = in.substring(1);
// this is the recursive call, and you know the input is getting
// smaller and smaller heading toward the stopping condition
createSubsets(lettersLeft);
// this is the "actual work" which doesn't get performed
// until after the above recursive call returns
for (int i = 0; i <= lettersLeft.length(); i++)
{
// possible "index out of bounds" here if subsets is
// smaller than lettersLeft
String temp = removed + subsets.get(i);
subsets.add(temp);
}
subsets.add(removed);
}
}
Something to remember when you are walking through your code trying to think through how it will run... You have structured your recursive method such that the execution pointer goes all the way down the recursion rabbit hole before doing any "real work", just pulling letters off of the input and pushing them onto the stack. All the "real work" is being done coming back out of the rabbit hole while letters are popping off of the stack. Therefore, the first 'a' in your subsets list is actually the last 'a' in your input string 'abba'. I.E. The first letter that is added to your subsets list is because lettersLeft.length() == 1. (in.length() == 1 in my example). Also, the debugger is your friend. Step-debugging is a great way to validate that your code is actually doing what you expect it to be doing at every step along the way.

Java | Create an explicit addition function only using recursion and conditionals

Preface
By finding some free time in my schedule, I quested myself into improving my recursion skills (unfortunately). As practice, I want to recreate all the operators by using recursion, the first one being addition. Although I'm kind of stuck.
Question
As implied, I want to recreate the addition operator by only using recursion and conditionals. Although I got a good portion of the code done, there is still one problem as I included a single addition operator. Here is the code (which runs fine and adds as intended in all variations of positive, negative, and zero inputs). I also included some mediocre comments as help.
public class Test {
public static void main(String[] args) {
// Numbers to add
int firstNumb = -5, secondNumb = 3;
// Call the add function and save the result
int result = add(firstNumb, secondNumb);
// Print result
System.out.println(result);
}
/*
* Function recursively takes a number from 'giver' one at a time and
* "gives"/"adds" it to 'receiver'. Once nothing more to "give" (second == 0),
* then return the number that received the value, 'receiver'.
*/
public static int add(int receiver, int giver) {
/*
* Base Case since nothing more to add on. != to handle signed numbers
* instead of using > or <
*/
if (giver != 0) {
/*
* Recursive Call.
*
* The new 'giver' param is the incremental value of the number
* towards 0. Ex: -5 -> -4 , 5 -> 4 (so I guess it may decrement).
*
* The new 'receiver' param is the incremental value based on the
* opposite direction the 'giver' incremented (as to why the
* directionalIncrement() function needs both values to determine
* direction.
*/
return add(directionalIncrement(receiver, giver),
directionalIncrement(giver, -giver));
} else {
// Return 'receiver' which now contains all values from 'giver'
return receiver;
}
}
// Increments (or decrements) the 'number' based on the sign of the 'direction'
public static int directionalIncrement(int number, int direction) {
// Get incremental value (1 or -1) by dividing 'direction' by absolute
// value of 'direction'
int incrementalValue = direction / abs(direction);
// Increment (or decrement I guess)
return number + incrementalValue;
}
// Calculates absolute value of a number
public static int abs(int number) {
// If number is positive, return number, else make it positive by multiplying by -1 then return
number = (number > 0.0F) ? number : -number;
return number;
}
}
The problem is the line that contains return number + incrementalValue;. As mentioned before, the code works with this although doesn't meet my own specifications of not involving any addition operators.
I changed the line to return add(number, incrementalValue); but seems like it cannot break out of the recursion and indeed throws the title of this website, a StackOverflowException.
All help appreciated. Thanks in advance.
Note
Constraint does not include any implicit increment/decrement (i++/i--) nor does it include bitwise. Try and answer towards the specific problem I am having in my own implementation.
public static int add(int a, int b) {
if(b == 0) return a;
int sum = a ^ b; //SUM of two integer is A XOR B
int carry = (a & b) << 1; //CARRY of two integer is A AND B
return add(sum, carry);
}
Shamefully taken from here. All credit goes to its author.
public static int add (int a, int b) {
if (b == 0) return a;
if (b > a) return add (b, a);
add (++a, --b);
}
Just with ++/--.

Check whether a string is parsable into Long without try-catch?

Long.parseLong("string") throws an error if string is not parsable into long.
Is there a way to validate the string faster than using try-catch?
Thanks
You can create rather complex regular expression but it isn't worth that. Using exceptions here is absolutely normal.
It's natural exceptional situation: you assume that there is an integer in the string but indeed there is something else. Exception should be thrown and handled properly.
If you look inside parseLong code, you'll see that there are many different verifications and operations. If you want to do all that stuff before parsing it'll decrease the performance (if we are talking about parsing millions of numbers because otherwise it doesn't matter). So, the only thing you can do if you really need to improve performance by avoiding exceptions is: copy parseLong implementation to your own function and return NaN instead of throwing exceptions in all correspondent cases.
From commons-lang StringUtils:
public static boolean isNumeric(String str) {
if (str == null) {
return false;
}
int sz = str.length();
for (int i = 0; i < sz; i++) {
if (Character.isDigit(str.charAt(i)) == false) {
return false;
}
}
return true;
}
You could do something like
if(s.matches("\\d*")){
}
Using regular expression - to check if String s is full of digits.
But what do you stand to gain? another if condition?
org.apache.commons.lang3.math.NumberUtils.isParsable(yourString) will determine if the string can be parsed by one of: Integer.parseInt(String), Long.parseLong(String), Float.parseFloat(String) or Double.parseDouble(String)
Since you are interested in Longs you could have a condition that checks for isParsable and doesn't contain a decimal
if (NumberUtils.isParsable(yourString) && !StringUtils.contains(yourString,".")){ ...
This is a valid question because there are times when you need to infer what type of data is being represented in a string. For example, you may need to import a large CSV into a database and represent the data types accurately. In such cases, calling Long.parseLong and catching an exception can be too slow.
The following code only handles ASCII decimal:
public class LongParser {
// Since tryParseLong represents the value as negative during processing, we
// counter-intuitively want to keep the sign if the result is negative and
// negate it if it is positive.
private static final int MULTIPLIER_FOR_NEGATIVE_RESULT = 1;
private static final int MULTIPLIER_FOR_POSITIVE_RESULT = -1;
private static final int FIRST_CHARACTER_POSITION = 0;
private static final int SECOND_CHARACTER_POSITION = 1;
private static final char NEGATIVE_SIGN_CHARACTER = '-';
private static final char POSITIVE_SIGN_CHARACTER = '+';
private static final int DIGIT_MAX_VALUE = 9;
private static final int DIGIT_MIN_VALUE = 0;
private static final char ZERO_CHARACTER = '0';
private static final int RADIX = 10;
/**
* Parses a string representation of a long significantly faster than
* <code>Long.ParseLong</code>, and avoids the noteworthy overhead of
* throwing an exception on failure. Based on the parseInt code from
* http://nadeausoftware.com/articles/2009/08/java_tip_how_parse_integers_quickly
*
* #param stringToParse
* The string to try to parse as a <code>long</code>.
*
* #return the boxed <code>long</code> value if the string was a valid
* representation of a long; otherwise <code>null</code>.
*/
public static Long tryParseLong(final String stringToParse) {
if (stringToParse == null || stringToParse.isEmpty()) {
return null;
}
final int inputStringLength = stringToParse.length();
long value = 0;
/*
* The absolute value of Long.MIN_VALUE is greater than the absolute
* value of Long.MAX_VALUE, so during processing we'll use a negative
* value, then we'll multiply it by signMultiplier before returning it.
* This allows us to avoid a conditional add/subtract inside the loop.
*/
int signMultiplier = MULTIPLIER_FOR_POSITIVE_RESULT;
// Get the first character.
char firstCharacter = stringToParse.charAt(FIRST_CHARACTER_POSITION);
if (firstCharacter == NEGATIVE_SIGN_CHARACTER) {
// The first character is a negative sign.
if (inputStringLength == 1) {
// There are no digits.
// The string is not a valid representation of a long value.
return null;
}
signMultiplier = MULTIPLIER_FOR_NEGATIVE_RESULT;
} else if (firstCharacter == POSITIVE_SIGN_CHARACTER) {
// The first character is a positive sign.
if (inputStringLength == 1) {
// There are no digits.
// The string is not a valid representation of a long value.
return null;
}
} else {
// Store the (negative) digit (although we aren't sure yet if it's
// actually a digit).
value = -(firstCharacter - ZERO_CHARACTER);
if (value > DIGIT_MIN_VALUE || value < -DIGIT_MAX_VALUE) {
// The first character is not a digit (or a negative sign).
// The string is not a valid representation of a long value.
return null;
}
}
// Establish the "maximum" value (actually minimum since we're working
// with negatives).
final long rangeLimit = (signMultiplier == MULTIPLIER_FOR_POSITIVE_RESULT)
? -Long.MAX_VALUE
: Long.MIN_VALUE;
// Capture the maximum value that we can multiply by the radix without
// overflowing.
final long maxLongNegatedPriorToMultiplyingByRadix = rangeLimit / RADIX;
for (int currentCharacterPosition = SECOND_CHARACTER_POSITION;
currentCharacterPosition < inputStringLength;
currentCharacterPosition++) {
// Get the current digit (although we aren't sure yet if it's
// actually a digit).
long digit = stringToParse.charAt(currentCharacterPosition)
- ZERO_CHARACTER;
if (digit < DIGIT_MIN_VALUE || digit > DIGIT_MAX_VALUE) {
// The current character is not a digit.
// The string is not a valid representation of a long value.
return null;
}
if (value < maxLongNegatedPriorToMultiplyingByRadix) {
// The value will be out of range if we multiply by the radix.
// The string is not a valid representation of a long value.
return null;
}
// Multiply by the radix to slide all the previously parsed digits.
value *= RADIX;
if (value < (rangeLimit + digit)) {
// The value would be out of range if we "added" the current
// digit.
return null;
}
// "Add" the digit to the value.
value -= digit;
}
// Return the value (adjusting the sign if needed).
return value * signMultiplier;
}
}
You can use java.util.Scanner
Scanner sc = new Scanner(s);
if (sc.hasNextLong()) {
long num = sc.nextLong();
}
This does range checking etc, too. Of course it will say that "99 bottles of beer" hasNextLong(), so if you want to make sure that it only has a long you'd have to do extra checks.
This case is common for forms and programs where you have the input field and are not sure if the string is a valid number. So using try/catch with your java function is the best thing to do if you understand how try/catch works compared to trying to write the function yourself. In order to setup the try catch block in .NET virtual machine, there is zero instructions of overhead, and it is probably the same in Java. If there are instructions used at the try keyword then these will be minimal, and the bulk of the instructions will be used at the catch part and that only happens in the rare case when the number is not valid.
So while it "seems" like you can write a faster function yourself, you would have to optimize it better than the Java compiler in order to beat the try/catch mechanism you already use, and the benefit of a more optimized function is going to be very minimal since number parsing is quite generic.
If you run timing tests with your compiler and the java catch mechanism you already described, you will probably not notice any above marginal slowdown, and by marginal I mean it should be almost nothing.
Get the java language specification to understand the exceptions more and you will see that using such a technique in this case is perfectly acceptable since it wraps a fairly large and complex function. Adding on those few extra instructions in the CPU for the try part is not going to be such a big deal.
I think that's the only way of checking if a String is a valid long value. but you can implement yourself a method to do that, having in mind the biggest long value.
There are much faster ways to parse a long than Long.parseLong. If you want to see an example of a method that is not optimized then you should look at parseLong :)
Do you really need to take into account "digits" that are non-ASCII?
Do you really need to make several methods calls passing around a radix even tough you're probably parsing base 10?
:)
Using a regexp is not the way to go: it's harder to determine if you're number is too big for a long: how do you use a regexp to determine that 9223372036854775807 can be parsed to a long but that 9223372036854775907 cannot?
That said, the answer to a really fast long parsing method is a state machine and that no matter if you want to test if it's parseable or to parse it. Simply, it's not a generic state machine accepting complex regexp but a hardcoded one.
I can both write you a method that parses a long and another one that determines if a long can be parsed that totally outperforms Long.parseLong().
Now what do you want? A state testing method? In that case a state testing method may not be desirable if you want to avoid computing twice the long.
Simply wrap your call in a try/catch.
And if you really want something faster than the default Long.parseLong, write one that is tailored to your problem: base 10 if you're base 10, not checking digits outside ASCII (because you're probably not interested in Japanese's itchi-ni-yon-go etc.).
Hope this helps with the positive values. I used this method once for validating database primary keys.
private static final int MAX_LONG_STR_LEN = Long.toString(Long.MAX_VALUE).length();
public static boolean validId(final CharSequence id)
{
//avoid null
if (id == null)
{
return false;
}
int len = id.length();
//avoid empty or oversize
if (len < 1 || len > MAX_LONG_STR_LEN)
{
return false;
}
long result = 0;
// ASCII '0' at position 48
int digit = id.charAt(0) - 48;
//first char cannot be '0' in my "id" case
if (digit < 1 || digit > 9)
{
return false;
}
else
{
result += digit;
}
//start from 1, we already did the 0.
for (int i = 1; i < len; i++)
{
// ASCII '0' at position 48
digit = id.charAt(i) - 48;
//only numbers
if (digit < 0 || digit > 9)
{
return false;
}
result *= 10;
result += digit;
//if we hit 0x7fffffffffffffff
// we are at 0x8000000000000000 + digit - 1
// so negative
if (result < 0)
{
//overflow
return false;
}
}
return true;
}
Try to use this regular expression:
^(-9223372036854775808|0)$|^((-?)((?!0)\d{1,18}|[1-8]\d{18}|9[0-1]\d{17}|92[0-1]\d{16}|922[0-2]\d{15}|9223[0-2]\d{14}|92233[0-6]\d{13}|922337[0-1]\d{12}|92233720[0-2]\d{10}|922337203[0-5]\d{9}|9223372036[0-7]\d{8}|92233720368[0-4]\d{7}|922337203685[0-3]\d{6}|9223372036854[0-6]\d{5}|92233720368547[0-6]\d{4}|922337203685477[0-4]\d{3}|9223372036854775[0-7]\d{2}|922337203685477580[0-7]))$
It checks all possible numbers for Long.
But as you know in Java Long can contain additional symbols like +, L, _ and etc. And this regexp doesn't validate these values. But if this regexp is not enough for you, you can add additional restrictions for it.
Guava Longs.tryParse("string") returns null instead of throwing an exception if parsing fails. But this method is marked as Beta right now.
You could try using a regular expression to check the form of the string before trying to parse it?
A simple implementation to validate an integer that fits in a long would be:
public static boolean isValidLong(String str) {
if( str==null ) return false;
int len = str.length();
if (str.charAt(0) == '+') {
return str.matches("\\+\\d+") && (len < 20 || len == 20 && str.compareTo("+9223372036854775807") <= 0);
} else if (str.charAt(0) == '-') {
return str.matches("-\\d+") && (len < 20 || len == 20 && str.compareTo("-9223372036854775808") <= 0);
} else {
return str.matches("\\d+") && (len < 19 || len == 19 && str.compareTo("9223372036854775807") <= 0);
}
}
It doesn't handle octal, 0x prefix or so but that is seldom a requirement.
For speed, the ".match" expressions are easy to code in a loop.

Categories

Resources