TangoKilo
TangoKilo

Reputation: 1785

How can I account for "," and "." when ensuring a String is a valid double?

I'm trying to ensure that a given string is a valid double. Most answers to this sort of question suggest using Double.parseDouble(inputString). However this isn't as robust as I'd hope. For instance if I enter a String such as "1one" Double.parseDouble("1one") will output "1" as opposed to returning an exception for an invalid double.

I've tried to get around this by iterating over the string and ensuring that every number is a digit:

    for (int i = 0; i < number.length(); i++) {
        previousChar = number.charAt(i);

        if (!Character.isDigit(number.charAt(i))
                && number.charAt(i) != '.' 
                                    && number.charAt(i) != ',') {
            return null;
        }
    } 

But for cases such as "20..02" or "20,,02" this will simply return 20. I was wondering what the best way to account for cases such as these would be.

Upvotes: 1

Views: 142

Answers (5)

ᴇʟᴇvᴀтᴇ
ᴇʟᴇvᴀтᴇ

Reputation: 12751

Good question. Depending on the users, you may need to be careful of differences between locales. Some places use , as a thousand separator others as a decimal point. You can find the locale-specific value using:

DecimalFormat formatter = (DecimalFormat) NumberFormat.getInstance();
DecimalFormatSymbols symbols = formatter.getDecimalFormatSymbols();
char decimalSeparator = symbols.getDecimalSeparator();

I would suggest writing a regular expression for your exact requirement rather than doing the matching manually. Remember to escape . if you want it to match . and not "any character".

Alternatively, you may be able to use parseDouble which does seem to throw an exception for "1one" after all:

System.out.println(Double.parseDouble("1one"));

For me, it produces:

Exception in thread "main" java.lang.NumberFormatException: For input string: "1one"
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1241)
at java.lang.Double.parseDouble(Double.java:540)

Upvotes: 3

GreySwordz
GreySwordz

Reputation: 356

Using a simple regex, you can check if it contains any non numerical characters like so:

String input = "1one2";
String numerical = input.replaceAll("[^0-9.]", "");
if (input.equals(numerical)) // If you remove all non numbers, still the same string

After which you can parse it for a double.

Upvotes: -2

Klas Lindb&#228;ck
Klas Lindb&#228;ck

Reputation: 33273

I would use Double.parseDouble, because, contrary to what you believe, it does throw a NumberFormatException for 1one.

public class k {
    public static void main(String argv[]) {
      double d = Double.parseDouble("1one");
    }
}

Output:

Exception in thread "Main Thread" java.lang.NumberFormatException: For input string: "1one"
    at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1222)
    at java.lang.Double.parseDouble(Double.java:510)
    at k.main(k.java:3)

If I wanted to allow both , and . and not just the decimal point specified by the locale, I would replace any , and . with the locale specified decmial point.

Upvotes: -1

Bathsheba
Bathsheba

Reputation: 234715

Parsing strings to doubles is fraught with danger. For example, in France, 1,234 is a number just a little greater than 1. They use . to separate round thousands and , to denote the start of the decimal portion.

The best way to check if a string is a valid number is to use NumberFormat to attempt to parse it and treat any exceptions thrown as an indication that the string is not a valid number. NumberFormat allows you to associate a locale:

NumberFormat nf = NumberFormat.getInstance(Locale.FRENCH/*for example*/);
double myNumber = nf.parse(myString); /*will throw an exception if not valid*/

Upvotes: 0

mohlendo
mohlendo

Reputation: 565

You could use the Validator framework and use the DoubleValidator from commons-validator.

DoubleValidator validator = DoubleValidator.getInstance();
validator.validate("1one");

Upvotes: 1

Related Questions