简体   繁体   中英

JAVA : NumberFormat exception when converting a string containing percent sign

I am using a third party java jar file that convert a string to integer.

The jar file is throwing NumberFormatException when the string contains a percent sign "%".

Below is the code of the Jar file.

String str = "com%paq"; // this is the input string
//the jar file code starts here
byte[] b = new byte[1];
b[0] = (byte)(Integer.parseInt( str.substring( 2, 2 + 2 ), 16 ) & 0xFF);
s[j++] = (new String( b, 0, 1, "ASCII" )).charAt( 0 );

The exception:

java.lang.NumberFormatException: For input string: "p%"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)

I cannot change the jar file code. The above code will always get executed whenever there is a "%" in the string.

Is there any way to avoid the exception?

That String has no digits, do the percent character is only part of the problem. There is no number to parse in str (unless you try to parse only the characters that can be treated as hex digits - c or a - which you don't).

You are trying to parse the substring p% , containing the characters p and % , which are not hexadecimal digits.

If you are supplying the input String to the jar, you can verify that the relevant characters are valid digits by validating the input before passing it to the jar. You call parseInt yourself, and only pass the String to the jar if you don't get a NumberFormatException .

boolean isValid = true;
String str = "com%paq"; // this is the input string
try {
    int test = Integer.parseInt( str.substring( 2, 2 + 2 ), 16 );
}
catch (NumberFormatException ex) {
    isValid = false;
}
if (isValid) { // invoke the jar code
    //the jar file code starts here
    byte[] b = new byte[1];
    b[0] = (byte)(Integer.parseInt( str.substring( 2, 2 + 2 ), 16 ) & 0xFF);
    s[j++] = (new String( b, 0, 1, "ASCII" )).charAt( 0 );
}

In addition to Erans answer I'd like to point you to the Java API documentation for Integer , which states:

An exception of type NumberFormatException is thrown if any of the following situations occurs:

  • The first argument is null or is a string of length zero.
  • The radix is either smaller than Character.MIN_RADIX or larger than Character.MAX_RADIX.
  • Any character of the string is not a digit of the specified radix, except that the first character may be a minus sign '-' ('\-') or plus sign '+' ('\+') provided that the string is longer than length 1.
  • The value represented by the string is not a value of type int.

The radix in the third party code you provided is 16, so it's hexadecimal. This would allow the decimal digits 0-9 and letter AF for the passed string.

From what I understood "com%paq" is a string you passed to the third party code yourself and it's not hardcoded in there. So you have to change it to something valid.

Integer.parseInt( str.substring( 2, 2 + 2 ), 16 ) evaluation result is "p%"

"p%" is not number, that's why NumberFormatException exception came in your code

Interger.parseInt(String str) convert only the string contains digits like "123", "675" etc.. it won't convert character string to integer. if you you want to convert string to integer use String.hashCode(); which gives a integer.

I can see that this code is trying to convert string to hexa-decimal number . as you have used Integer.parseInt("String",radix) .

quickly i tried to run few tests

  Integer.parseInt("e", 16) ;// prints 14 
  Integer.parseInt("f", 16) ;// prints 15
  Integer.parseInt("g", 16) ;// throws NumberFormat Exception 

basic here is even if you want to convert hexadecmial characters to a number you are limited with characters 'a' ,'b' ... 'f' , if your string contains letters apart from these letter ,it will surely fail with NumberformatException .

as you can see String str = "com%paq" contains invalid letters like m , % , p , q . so even with substring (2,2+2) will give you m% which is still invalid hexadecimal string.

Is there any way to avoid the exception?

One way could be first validate whether input string has correct characters then only call the method from jar .

for example suppose that the Integer conversion logic is present in getNumber() method in third party jar as shown below . (pseudo code for demo purpose)

public byte[] getNumber(String str){
//the jar file code starts here
byte[] b = new byte[1];
b[0] = (byte)(Integer.parseInt( str.substring( 2, 2 + 2 ), 16 ) & 0xFF);
s[j++] = (new String( b, 0, 1, "ASCII" )).charAt( 0 );
.
.
.
  return b;
}

then put a validation on string before calling to getNumber

if(str.matches("^[-+]?[0-9 a-f A-F]+")) //String validation logic .
{
    byte[] b = getNumber(str);
}

this way you can avoid the exception.

  1. Here you can send custom message if String is not validated

  2. Also you can put more validation on String as per requirement

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM