Best way to parseDouble with comma as decimal separator?

Java

Java Problem Overview


Because of the comma used as the decimal separator, this code throws a NumberFormatException:

String p="1,234";
Double d=Double.valueOf(p);	
System.out.println(d);

Is there a better way to parse "1,234" to get 1.234 than: p = p.replaceAll(",",".");?

Java Solutions


Solution 1 - Java

Use java.text.NumberFormat:

NumberFormat format = NumberFormat.getInstance(Locale.FRANCE);
Number number = format.parse("1,234");
double d = number.doubleValue();

Updated:

To support multi-language apps use:

NumberFormat format = NumberFormat.getInstance(Locale.getDefault());

Solution 2 - Java

You can use this (the French locale has , for decimal separator)

NumberFormat nf = NumberFormat.getInstance(Locale.FRANCE);
nf.parse(p);

Or you can use java.text.DecimalFormat and set the appropriate symbols:

DecimalFormat df = new DecimalFormat();
DecimalFormatSymbols symbols = new DecimalFormatSymbols();
symbols.setDecimalSeparator(',');
symbols.setGroupingSeparator(' ');
df.setDecimalFormatSymbols(symbols);
df.parse(p);

Solution 3 - Java

As E-Riz points out, NumberFormat.parse(String) parse "1,23abc" as 1.23. To take the entire input we can use:

public double parseDecimal(String input) throws ParseException{
  NumberFormat numberFormat = NumberFormat.getNumberInstance(Locale.getDefault());
  ParsePosition parsePosition = new ParsePosition(0);
  Number number = numberFormat.parse(input, parsePosition);

  if(parsePosition.getIndex() != input.length()){
    throw new ParseException("Invalid input", parsePosition.getIndex());
  }

  return number.doubleValue();
}

Solution 4 - Java

Double.parseDouble(p.replace(',','.'))

...is very quick as it searches the underlying character array on a char-by-char basis. The string replace versions compile a RegEx to evaluate.

Basically replace(char,char) is about 10 times quicker and since you'll be doing these kind of things in low-level code it makes sense to think about this. The Hot Spot optimiser will not figure it out... Certainly doesn't on my system.

Solution 5 - Java

If you don't know the correct Locale and the string can have a thousand separator this could be a last resort:

    doubleStrIn = doubleStrIn.replaceAll("[^\\d,\\.]++", "");
    if (doubleStrIn.matches(".+\\.\\d+,\\d+$"))
        return Double.parseDouble(doubleStrIn.replaceAll("\\.", "").replaceAll(",", "."));
    if (doubleStrIn.matches(".+,\\d+\\.\\d+$"))
        return Double.parseDouble(doubleStrIn.replaceAll(",", ""));
    return Double.parseDouble(doubleStrIn.replaceAll(",", "."));

Be aware: this will happily parse strings like "R 1 52.43,2" to "15243.2".

Solution 6 - Java

This is the static method I use in my own code:

public static double sGetDecimalStringAnyLocaleAsDouble (String value) {
	
	if (value == null) {
		Log.e("CORE", "Null value!");
		return 0.0;
	}
	
	Locale theLocale = Locale.getDefault();
	NumberFormat numberFormat = DecimalFormat.getInstance(theLocale);
	Number theNumber;
	try {
		theNumber = numberFormat.parse(value);
		return theNumber.doubleValue();
	} catch (ParseException e) {
		// The string value might be either 99.99 or 99,99, depending on Locale.
		// We can deal with this safely, by forcing to be a point for the decimal separator, and then using Double.valueOf ...
 		//http://stackoverflow.com/questions/4323599/best-way-to-parsedouble-with-comma-as-decimal-separator
 		String valueWithDot = value.replaceAll(",",".");
 		
 		try {
		  return Double.valueOf(valueWithDot);
 		} catch (NumberFormatException e2)  {
 			// This happens if we're trying (say) to parse a string that isn't a number, as though it were a number!
 			// If this happens, it should only be due to application logic problems.
 			// In this case, the safest thing to do is return 0, having first fired-off a log warning.
 			Log.w("CORE", "Warning: Value is not a number" + value);
 			return 0.0;
 		}
	}
}

Solution 7 - Java

In Kotlin you can use extensions as below:

fun String.toDoubleEx() : Double {
   val decimalSymbol = DecimalFormatSymbols.getInstance().decimalSeparator
  return if (decimalSymbol == ',') {
      this.replace(decimalSymbol, '.').toDouble()
  } else {
      this.toDouble()
  }
}

and you can use it everywhere in your code like this:

val myNumber1 = "5,2"
val myNumber2 = "6.7"

val myNum1 = myNumber1.toDoubleEx()
val myNum2 = myNumber2.toDoubleEx()

It is easy and universal!

Solution 8 - Java

You of course need to use the correct locale. This question will help.

Solution 9 - Java

In the case where you don't know the locale of the string value received and it is not necessarily the same locale as the current default locale you can use this :

private static double parseDouble(String price){
    String parsedStringDouble;
    if (price.contains(",") && price.contains(".")){
        int indexOfComma = price.indexOf(",");
        int indexOfDot = price.indexOf(".");
        String beforeDigitSeparator;
        String afterDigitSeparator;
        if (indexOfComma < indexOfDot){
            String[] splittedNumber = price.split("\\.");
            beforeDigitSeparator = splittedNumber[0];
            afterDigitSeparator = splittedNumber[1];
        }
        else {
            String[] splittedNumber = price.split(",");
            beforeDigitSeparator = splittedNumber[0];
            afterDigitSeparator = splittedNumber[1];
        }
        beforeDigitSeparator = beforeDigitSeparator.replace(",", "").replace(".", "");
        parsedStringDouble = beforeDigitSeparator+"."+afterDigitSeparator;
    }
    else {
        parsedStringDouble = price.replace(",", "");
    }

    return Double.parseDouble(parsedStringDouble);

}

It will return a double no matter what the locale of the string is. And no matter how many commas or points there are. So passing 1,000,000.54 will work so will 1.000.000,54 so you don't have to rely on the default locale for parsing the string anymore. The code isn't as optimized as it can be so any suggestions are welcome. I tried to test most of the cases to make sure it solves the problem but I am not sure it covers all. If you find a breaking value let me know.

Solution 10 - Java

This would do the job:

Double.parseDouble(p.replace(',','.')); 

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKoerrView Question on Stackoverflow
Solution 1 - JavadogbaneView Answer on Stackoverflow
Solution 2 - JavaBozhoView Answer on Stackoverflow
Solution 3 - JavaswashbucklerView Answer on Stackoverflow
Solution 4 - JavaRocketBananaView Answer on Stackoverflow
Solution 5 - Javauser3506443View Answer on Stackoverflow
Solution 6 - JavaPeteView Answer on Stackoverflow
Solution 7 - JavamojiView Answer on Stackoverflow
Solution 8 - JavakgiannakakisView Answer on Stackoverflow
Solution 9 - JavaAmro elaswarView Answer on Stackoverflow
Solution 10 - JavaHelgeView Answer on Stackoverflow