Check if string is syntactic in Long without try-catch?

Long.parseLong("string") throws an error if the string does not parse in length. Is there a way to check a string faster than using try-catch ? Thanks

+58
java string parsing try-catch
Apr 01 '10 at 20:53 on
source share
14 answers

You can create a rather complex regex, but it's not worth it. The exception here is absolutely normal.

This is a natural exception: you are assuming there is an integer in the string, but there really is something else. An exception must be selected and handled properly.

If you look at the parseLong code, you will see that there are many different checks and operations. If you want to do all this before parsing, it will reduce performance (if we are talking about parsing millions of numbers, because otherwise it does not matter). Thus, the only thing you can do if you really need to improve performance is by avoiding exceptions: copy parseLong implementation into your own function and return NaN instead of throwing exceptions in all cases of correlation.

+46
Apr 01 2018-10-01T00:
source share
โ€” -

From the public StringUtils strings:

 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; } 
+26
Apr 01 '10 at 20:59 on
source share

You can do something like

 if(s.matches("\\d*")){ } 

Using regex - to check if string s is filled with numbers. But what will you gain? another if condition?

+10
Apr 01 '10 at 21:01
source share

You can use java.util.Scanner

 Scanner sc = new Scanner(s); if (sc.hasNextLong()) { long num = sc.nextLong(); } 

It is also a range check, etc. Of course, he will say that "99 bottles of beer" hasNextLong() , so if you want it to only have long , you will need to perform additional checks.

+5
Apr 02 '10 at 6:15
source share

This is the right question, because there are times when you need to specify what type of data will be presented in the string. For example, you may need to import a large CSV into a database and accurately represent data types. In such cases, calling Long.parseLong and catching the exception may be too slow.

The following code only processes ASCII:

 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; } } 
+5
Jul 19 '14 at 3:02
source share

org.apache.commons.lang3.math.NumberUtils.isParsable (yourString) will determine if the string can be parsed by one of the following: Integer.parseInt (String), Long.parseLong (String), Float.parseFloat (String) or Double. parseDouble (String)

Since you are interested in Longs, you may have a condition that checks isParsable and does not contain a decimal number

 if (NumberUtils.isParsable(yourString) && !StringUtils.contains(yourString,".")){ ... 
+4
May 10 '17 at a.m.
source share

This case is common for forms and programs in which you have an input field, and are not sure if the string is a valid number. So using try / catch with a java function is the best thing to do if you understand how try / catch works compared to trying to write a function yourself. To set up a catch try block on a .NET virtual machine, there are zero overhead instructions, and it probably looks like Java. If there are instructions in the try key, they will be minimal, and the bulk of the instructions will be used in the catch part, and this will happen only in the rare case when the number is invalid.

So while it โ€œseemsโ€ like you can write a faster function yourself, you will have to optimize it better than the Java compiler to outperform the try / catch mechanism you are already using, and the advantage of a more optimized function will be very minimal, since parsing numbers is pretty common.

If you run time tests with your compiler and the java catch mechanism, which you have already described, you probably won't notice any excess of the maximum slowdown, and by marginal I mean that it should be almost nothing.

Get the java language specification to better understand the exceptions, and you will see that using this method in this case is quite acceptable, since it wraps a rather large and complex function. Adding these few additional instructions to the CPU for the try part will not be such a big deal.

+3
Sep 18 '11 at 10:22
source share

I think the only way to check if String is a valid long value. but you can realize a way to do this, bearing in mind the greatest value.

+2
Apr 01 2018-10-01T00:
source share

There is a much faster way to parse long than Long.parseLong. If you want to see an example of a method that is not optimized, you should look at parseLong :)

Do you really need to consider โ€œnumbersโ€ that are not ASCII?

You really need to make several calling methods that go around the radix, even hard, you probably parse base 10?

:)

Using a regular expression is not the way: itโ€™s harder to determine if you are too long for a long time: how do you use a regular expression to determine what 9223372036854775807 can take longer, but 9223372036854775907 cannot?

However, the answer to a very fast parsing method is a finite state machine and that no matter whether you want to check whether it is being processed or parsed. Itโ€™s just not a general finite state machine that takes a complex regular expression, but a hard-coded one.

I can write you a method that analyzes a long one and another that determines if a long analysis can be completely superior to Long.parseLong ().

Now what do you need? State testing method? In this case, the state testing method may be undesirable if you want to avoid computing twice as long.

Just wrap your call in try / catch.

And if you really want something faster than the default value of Long.parseLong, write what corresponds to your problem: base 10 if you are base 10 without checking numbers outside of ASCII (because you are probably not interested in Japanese itchi- ni-yon-go, etc.).

+2
Apr 01 '10 at
source share

Hope this helps with positive values. I used this method once to verify the primary keys of the database.

 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; } 
+2
Dec 18 '14 at 13:41
source share

Try using this regex:

^(-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]))$

He checks all possible numbers for Long. But, as you know, Java Long may contain additional characters, such as + , L , _ , etc. And this regular expression does not check these values. But if this regular expression is not enough for you, you can add additional restrictions for it.

+2
Dec 13 '16 at 9:50
source share

Can you try using a regular expression to check the shape of a string before trying to parse it?

0
Apr 01 '10 at 21:01
source share

Guava Longs.tryParse ("string") returns null instead of throwing an exception if the parsing failed. But this method is marked as beta right now.

0
Sep 10 '18 at 1:15
source share

A simple implementation for checking an integer suitable for long would look like this:

  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 does not handle octal, 0x or so prefix, but this is rarely required.

To speed up the expression ".match" is easy to code in a loop.

0
Apr. 09 '19 at 12:29
source share



All Articles