Reputation: 15733
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(",",".");
?
Upvotes: 186
Views: 231517
Reputation: 274858
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());
Upvotes: 246
Reputation: 286
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!
Upvotes: 4
Reputation: 3525
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.
Upvotes: 1
Reputation: 225
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.
Upvotes: 20
Reputation: 794
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;
}
}
}
Upvotes: 4
Reputation: 437
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();
}
Upvotes: 22
Reputation: 91
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".
Upvotes: 6
Reputation: 597392
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);
Upvotes: 77
Reputation: 104196
You of course need to use the correct locale. This question will help.
Upvotes: 2