用逗号作为小数点来解析 double 的最佳方法是什么?

由于使用 逗号作为 小数点,这段代码抛出一个 NumberFormatException:

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

有没有比: p = p.replaceAll(",",".");更好的解析 "1,234"得到 1.234的方法?

206238 次浏览

你可以使用这个(法语地区的小数点是 ,)

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

或者你可以使用 java.text.DecimalFormat并设置适当的符号:

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

使用 文本。数字格式:

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

更新:

支持多语言应用程序的使用:

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

当然,您需要使用正确的语言环境。 这个问题会有所帮助。

正如 E-Riz 指出的,NumberFormat.parse (String)将“1.23 abc”解析为1.23:

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();
}

这是我在自己的代码中使用的静态方法:

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;
}
}
}

如果你不知道正确的语言环境,字符串可以有一千个分隔符,这可能是最后的手段:

    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(",", "."));

注意: 这将很好地解析字符串,比如“ R152.43.2”到“15243.2”。

这样就可以了:

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

是非常快的,因为它搜索底层字符数组的字符逐个字符的基础上。字符串替换版本编译一个 RegEx 来计算。

基本上,替换(char,char)的速度要快10倍左右,而且因为您将在低级代码中执行这些操作,所以考虑这个问题是有意义的。“热点”优化器不会解决这个问题... ... 在我的系统上当然不会。

如果您不知道接收到的字符串值的区域设置,并且它不一定与当前默认区域设置相同,那么您可以使用:

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);


}

不管字符串的区域设置是什么,它都会返回一个 double。不管有多少逗号或点。所以传递 1,000,000.541.000.000,54都是有效的,这样你就不必再依赖默认的语言环境来解析字符串了。代码并没有优化到它可以达到的程度,所以欢迎任何建议。我试图测试大多数的情况下,以确保它解决了问题,但我不确定它涵盖了所有。如果你发现一个破碎值让我知道。

在 Kotlin,你可以使用以下扩展:

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

你可以像这样在代码的任何地方使用它:

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


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

简单又通用!