7

Edit: Clarification convert any valid number encoding from a string to a number

How does one convert a string to a number, say just for integers, for all accepted integer formats, particularly the ones that throw NumberFormatException under Integer.parseInt. For example, the code

...
int i = 0xff;
System.out.println(i);
String s = "0xff";
System.out.println( Integer.parseInt(s) );
....

Will throw a NumberFormatException on the fourth line, even though the string is clearly a valid encoding for a hexadecimal integer. We can assume that we already know that the encoding is a valid number, say by checking it against a regex. It would be nice to also check for overflow (like Integer.parseInt does), but it would be okay if that has to be done as a separate step.

I could loop through every digit and manually calculate the composite, but that would pretty difficult. Is there a better way?

EDIT: a lot of people are answering this for hexidecimal, which is great, but not completely what I was asking (it's my fault, I used hexidecimal as the example). I'm wondering if there's a way to decode all valid java numbers. Long.decode is definitely great for just catching hex, but it fails on

222222L

which is a perfectly valid long. Do I have to catch for every different number format separately? I'm assuming you've used a regex to tell what category of number it is, i.e, distinguish floats, integers, etc.

en_Knight
  • 5,301
  • 2
  • 26
  • 46
  • 1
    Does this help? http://stackoverflow.com/questions/5153811/how-to-convert-a-hexadecimal-string-to-long-in-java – DJG Apr 30 '14 at 20:31
  • 1
    If you drop the `0x`, you can call `Integer.parseInt(s, 16)`. – Blorgbeard Apr 30 '14 at 20:31
  • @dg123 That does help for hex, but doesn't solve the problem in general - doesn't catch 111_111_111 or 1111111L, for example. – en_Knight Apr 30 '14 at 20:45
  • @Blorgbeard This also isn't a general solution. I could certainly manually check for all cases, though that does look like a good way to check for hex numbers – en_Knight Apr 30 '14 at 20:45
  • @en_Knight there's no silver bullet solution here since your input `String` can be a variety of numeric formats which require different conversion methods. Look to producing a input `String` consistently in one format – Reimeus Apr 30 '14 at 21:10
  • 1
    Don't confuse numbers with numeric literals. The latter is just syntactic sugar. – Sotirios Delimanolis Apr 30 '14 at 21:13
  • @Reimus hmm is that true even if the type of the number is known, as in I know that it's an integer, long, float, etc.? There are only a few, enumerated formats for each in the JLS - there isn't a method for decoding them? – en_Knight Apr 30 '14 at 21:15
  • @Sotirios Delimanolis good call - did I remove the mistake? – en_Knight Apr 30 '14 at 21:16
  • @en_Knight not if you're using something like a `Long` literal... – Reimeus Apr 30 '14 at 21:29
  • You could always write a parser (or maybe just a regex) to parse anything you want... – DJG Apr 30 '14 at 21:41

4 Answers4

5

You need to specify the base of the number you are trying to parse:

Integer.parseInt(s,16);

This will fail if you have that "0x" starting it off so you could just add a check:

if (s.startsWith("0x")) {
    s = s.substring(2);
}
Integer.parseInt(s,16);

EDIT

In response to the information that this was not a hex specific question I would recommend writing your own method to parse out all the numbers formats you like and build in on top of Integer.decode which can save you from having to handle a couple of cases.

I would say use regex or create your own methods to validate other formats:

public static int manualDecode(String s) throws NumberFormatException {

    // Match against #####L long format
    Pattern p = Pattern.compile("\\d+L");  // Matches ########L
    Matcher m = p.matcher(s);
    if (m.matches()) {
        return Integer.decode(s.substring(0,s.length()-1));
    }

    // Match against that weird underscore format
    p = Pattern.compile("(\\d{1,3})_((\\d{3})_)*?(\\d{3})"); // Matches ###_###_###_###_###
    m = p.matcher(s);
    if (m.matches()) {
        String reformattedString = "";
        char c;
        for (int i = 0; i < s.length(); i++) {
            c = s.charAt(i);
            if ( c >= '0' && c <= '9') {
                reformattedString += c;
            }
        }
        return Integer.decode(reformattedString);
    }
    // Add as many more as you wish
    throw new NumberFormatException();
}

public int parseIntExtended(String s) {
    try {
        return Integer.decode(s);
    } catch (NumberFormatException e) {
        return manualDecode(s);
    }
}
Farmer Joe
  • 6,020
  • 1
  • 30
  • 40
5

You could do

System.out.println(Integer.decode(s));
Reimeus
  • 158,255
  • 15
  • 216
  • 276
  • This is 100% the way to go! – 2rs2ts Apr 30 '14 at 20:35
  • Worth noticing that this only works for an hexadecimal value that represent a positive integer. Ex: `System.out.println(Integer.decode("0xfffffff4"));` will throw a `NumberFormatException`. – Alexis C. Apr 30 '14 at 20:39
  • This is great for just hex, but will not decode all integers. For example, 111_111_111 is a valid integer, but will throw a number format exception – en_Knight Apr 30 '14 at 20:42
0

Integer.decode should do the trick:

public class a{
    public static void main(String[] args){
        String s="0xff";
        System.out.println(Integer.decode(s));
    }
}
ailnlv
  • 1,779
  • 1
  • 15
  • 29
0

You can try using BigInteger also but sill you have to remove 0x first or replace x from 0

int val = new BigInteger("ff", 16).intValue(); // output 255
Braj
  • 46,415
  • 5
  • 60
  • 76