1

I'd like to convert string representations of integers to actual integer values. I do not know which radix/base is being used beforehand, so I cannot simply rely on methods/constructors that take the radix as an argument (like shown here). The strings may represent unsigned 64bit integers and other large numbers, so using java.lang.Integer is not an option.

Is there a better way of doing what I'm attempting to do with code below? Are there constructors/methods available right there in java that would allow interpretation of a string as an integer literal on their own? I know Python offers to do this when the specified radix is 0 (int()).

import java.math.BigInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class LexicalIntegerCoverter {

    private static final Pattern pattern = 
            Pattern.compile("(\\+|-)?(0(x)?)?([0-9a-fA-F]+)");    

    private Parts getParts(String lex) { // pun was not intended
        Matcher matcher = pattern.matcher(lex);
        boolean lookingAt = matcher.lookingAt();
        if (lookingAt) {
            String sign = matcher.group(1);
            int radix;
            String prefix = matcher.group(2);
            if ("0".equals(prefix)) {
                radix = 8;
            } else if ("0x".equals(prefix)) {
                radix = 16;
            } else {
                radix = 10;
            }
            String numbers = matcher.group(4);
            return new Parts(sign, radix, numbers);
        }
        throw new NumberFormatException("Unknown lexical representation");
    }

    public BigInteger getLexToInt(String lex) {
        Parts parts = getParts(lex.trim());
        return new BigInteger(parts.getNumber(), parts.getRadix());
    }

    public static void main(String[] args) {
        String hexLex = "0xf";
        String hexLexPlus = "+0xf";
        String hexLexMinus = "-0xf";
        String octLex = "017";
        String octLexPlus = "+017";
        String octLexMinus = "-017";
        String decLex = "15";
        String decLexPlus = "+15";
        String decLexMinus = "-15";

        LexicalIntegerCoverter converter = new LexicalIntegerCoverter();
        System.out.println(hexLex + " = " + converter.getLexToInt(hexLex));
        System.out.println(hexLexPlus + " = " + converter.getLexToInt(hexLexPlus));
        System.out.println(hexLexMinus + " = " + converter.getLexToInt(hexLexMinus));
        System.out.println(octLex + " = " + converter.getLexToInt(octLex));
        System.out.println(octLexPlus + " = " + converter.getLexToInt(octLexPlus));
        System.out.println(octLexMinus + " = " + converter.getLexToInt(octLexMinus));
        System.out.println(decLex + " = " + converter.getLexToInt(decLex));
        System.out.println(decLexPlus + " = " + converter.getLexToInt(decLexPlus));
        System.out.println(decLexMinus + " = " + converter.getLexToInt(decLexMinus));
    }

    private static class Parts {
        private final String sign;
        private final int radix;
        private final String digits;

        public Parts(String sign, int radix, String digits) {
            this.sign = sign;
            this.radix = radix;
            this.digits = digits;
        }

        public String getSign() {
            return sign;
        }

        public int getRadix() {
            return radix;
        }

        public String getDigits() {
            return digits;
        }

        public String getNumber() {
            return (sign == null ? "" : sign) + digits;
        }

        @Override
        public String toString() {
            return getNumber() + "[" + radix + "]";
        }

    }
}

P.S.: there's a lot of similar questions about this, where answers point to Integer.parseInt(String, int) or BigInteger(String, int), but that's not the answer I'm looking for. I'd also prefer doing this without relying on third party libraries. I'm also aware of the fact that java allows integer literals to be defined in code, which is also not the answer I'm looking for (I actually need to convert strings that contain integer literals) - I would like to do what a java compiler does when it encounters such values.

Edit01

I said above that I'd prefer not using a third party library, but that doesn't mean it's not an option.

Community
  • 1
  • 1
predi
  • 5,528
  • 32
  • 60
  • @R.J: `Integer.MAX_VALUE` may be less than equal to values represented by my strings. – predi Nov 29 '13 at 09:34
  • Using third party library is good sometimes for specific reasons. In your case you can use [NumberUtils](http://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/math/NumberUtils.html) from **apache commons** – Foolish Nov 29 '13 at 09:36
  • @Foolish: are you referring to [NumberUtils.createBigInteger(String)](http://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/math/NumberUtils.html#createBigInteger(java.lang.String))? Does it handle the notations in my main method? – predi Nov 29 '13 at 09:41

2 Answers2

0
BigInteger bi = new BigInteger(s, 16);

This will parse string as a hexadecimal number, yuo just need to remove 0x (or other) prefixes. Also take a look on DecimalFormat class of standart javaSE api http://docs.oracle.com/javase/7/docs/api/java/text/DecimalFormat.html

StrekoZ
  • 618
  • 6
  • 12
0

If you don't want to use any third party library, and you restrict yourself to Integer values, you can use Java Integer.decode.

If you need BigIntegers, maybe something as simple as the following could do the job:

public BigInteger getLexToInt(String s)
{
    if (s.startsWith("0x"))
        return new BigInteger(s.substring(2), 16);
    else if (s.startsWith("+0x"))
        return new BigInteger(s.substring(3), 16);
    else if (s.startsWith("-0x"))
        return new BigInteger(s.replaceFirst("0x",""), 16);
    else if (s.startsWith("0"))
        return new BigInteger(s.substring(1), 8);
    else if (s.startsWith("+0"))
        return new BigInteger(s.substring(2), 8);
    else if (s.startsWith("-0"))
        return new BigInteger(s.replaceFirst("0",""), 8);
    else
        return new BigInteger(s);
}
neutrino
  • 2,297
  • 4
  • 20
  • 28
  • This would be exactly what I am looking for, but the return value is a `java.lang.Integer` and it uses `Integer.parseInt(String, int)` internally. Can't handle large numbers. – predi Nov 29 '13 at 10:03