用逗号作为小数点分隔符来解析Double的最佳方法?


148

以下结果是Exception

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

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


17
以我的经验,按照您的建议,replaceAll()是执行此操作的最佳方法。它不依赖于当前的语言环境,它很简单并且可以正常工作。
Joonas Pulakka 2010年

1
@Marco Altieri:replaceAll(",",".")用点替换所有逗号。如果没有逗号,则不执行任何操作。Double.valueOf()(仅)适用于使用点作为小数点分隔符的字符串。当前的默认语言环境不会影响此处的任何内容。docs.oracle.com/javase/8/docs/api/java/lang/...
Joonas Pulakka

4
唯一的问题replaceAll(",",".")是它只有在有一个逗号的情况下才有效:即:1,234,567将抛出 java.lang.NumberFormatException: multiple points。具有正向前瞻性的正则表达式可满足p.replaceAll(",(?=[0-9]+,)", "").replaceAll(",", ".")更多要求:regular-expressions.info/lookaround.html
artemisian

2
没有问题。NumberFormatException是好的。您怎么知道哪个逗号是正确的?格式错误,您所能做的就是向用户显示比异常更好的可读性消息。
令人难以置信的

2
@TheincredibleJan不,格式没有错误。一些语言环境使用逗号作为千位分隔符,因此您可以在数字中使用多个逗号,并且从技术上讲,这仍然是有效的输入。
Vratislav Jindra '18

Answers:


206

使用java.text.NumberFormat

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

11
仅当当前默认语言环境恰好使用逗号作为小数点分隔符时,此方法才有效。
Joonas Pulakka 2010年

6
为了进一步解决问题,某些语言环境使用逗号作为千位分隔符,在这种情况下,“ 1,234”将解析为1234.0而不是抛出错误。
Joonas Pulakka 2010年

17
NumberFormat的问题在于它将静默忽略无效字符。因此,如果您尝试解析“ 1,23abc”,它将很高兴地返回1.23,而没有向您指示传入的String包含不可解析的字符。在某些情况下,这实际上可能是理想的,但我认为这通常不是理想的行为。
E-Riz 2013年

7
火鸡,你应该使用NumberFormat.getInstance(新区域(tr_TR))
居纳伊居尔泰金

2
对谁使用什么分隔符看到en.wikipedia.org/w/...
fiffy

67

您可以使用它(法语语言环境具有,小数点分隔符)

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

是的...如果我们不设置千位分隔符,而仅使用法语格式,则将西班牙语格式的数字(1.222.222,33)转换为“ 1 222 222,33”,这不是我想要的。那谢谢啦!
WesternGun

1
另一件事是,西班牙语言环境中不被列为“default`,我不能构建一个Locale与正确的格式new Locale("es", "ES"),然后自动解析数字符串NumberFormat,以,作为小数点分隔符和.作为千个组分隔符仅DecimalFormat工作。
WesternGun

为什么不是所有国家都在那里?我觉得不可思议关于使用法语区域设置格式化波兰数...
在线

18

正如E-Riz所指出的,NumberFormat.parse(String)将“ 1,23abc”解析为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();
}


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

...非常快,因为它逐个字符地搜索基础字符数组。字符串替换版本会编译RegEx进行评估。

基本上,replace(char,char)大约快10倍,并且由于您将在低级代码中执行此类操作,因此考虑一下是有意义的。热点优化器将无法解决...当然不在我的系统上。


4

如果您不知道正确的语言环境,并且字符串可以有千位分隔符,那么这可能是最后的选择:

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

请注意:这将很高兴地将字符串解析为“ R 1 52.43,2”至“ 15243.2”。


4

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

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

5
如果默认的语言环境类似于德语,逗号表示小数点后该怎么办?您可以传入,例如“ 1,000,000”,它不会解析为德语语言环境,然后将其替换为“ 1.000.000”,这不是有效的Double。
Eddie Curtis 2015年

@jimmycar,您好,我刚刚更新了答案,以使用当前版本的静态方法。希望这能解决您的问题!皮特
皮特2015年


0

如果您不知道接收到的字符串值的语言环境,并且该语言环境不一定与当前的默认语言环境相同,则可以使用以下方法:

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.54将起作用,1.000.000,54因此您不必再依赖默认语言环境来解析字符串。该代码没有得到最佳优化,因此欢迎您提出任何建议。我试图测试大多数情况,以确保它可以解决问题,但是我不确定它是否涵盖所有问题。如果您发现突破性的价值,请告诉我。


-5

这将完成工作:

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

6
最初的问题是:“比起= = p.replaceAll(“,”,“。”),还有更好的方法来解析“ 1,234”以获得1.234。,如果您认为replace与使用有很大不同replaceAll,请说明原因。
SuperBiasedMan 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.