用逗号作为小数分隔符解析Double的最佳方法?
Posted
技术标签:
【中文标题】用逗号作为小数分隔符解析Double的最佳方法?【英文标题】:Best way to parseDouble with comma as decimal separator? 【发布时间】:2011-05-18 10:32:43 【问题描述】:由于comma 用作decimal separator,此代码抛出NumberFormatException
:
String p="1,234";
Double d=Double.valueOf(p);
System.out.println(d);
有没有比p = p.replaceAll(",",".");
更好的方法来解析"1,234"
以获得1.234
?
【问题讨论】:
根据我的经验,按照您的建议,replaceAll() 是最好的方法。它不依赖于当前的语言环境,它很简单,而且很有效。 @Marco Altieri:replaceAll(",",".")
用点替换所有逗号。如果没有逗号,那么它什么也不做。 Double.valueOf()
(仅)适用于使用点作为小数分隔符的字符串。当前默认语言环境不影响此处的任何内容。 docs.oracle.com/javase/8/docs/api/java/lang/…
replaceAll(",",".")
的唯一问题是它只有在有一个逗号时才有效:即:1,234,567 将抛出 java.lang.NumberFormatException: multiple points
。具有正向前瞻的正则表达式就足够了 p.replaceAll(",(?=[0-9]+,)", "").replaceAll(",", ".")
更多信息:regular-expressions.info/lookaround.html
没有问题。 NumberFormatException 很好。你怎么知道哪个逗号是正确的?格式错误,您所能做的就是向用户显示比异常更易读的消息。
@TheincredibleJan 不,格式没有错。某些语言环境使用逗号作为千位分隔符,因此您可以在一个数字中包含多个逗号,并且从技术上讲它仍然是有效的输入。
【参考方案1】:
使用java.text.NumberFormat:
NumberFormat format = NumberFormat.getInstance(Locale.FRANCE);
Number number = format.parse("1,234");
double d = number.doubleValue();
更新:
要支持多语言应用,请使用:
NumberFormat format = NumberFormat.getInstance(Locale.getDefault());
【讨论】:
这仅适用于当前默认语言环境碰巧使用逗号作为小数分隔符的情况。 为了进一步搞砸,一些语言环境使用逗号作为 千位分隔符,在这种情况下,“1,234”将解析为 1234.0 而不是引发错误。 NumberFormat 的问题在于它会默默地忽略无效字符。因此,如果您尝试解析“1,23abc”,它会很高兴地返回 1.23,而不会告诉您传入的字符串包含不可解析的字符。在某些情况下,这实际上可能是理想的,但我认为这通常不是理想的行为。 对于土耳其,您应该使用 NumberFormat.getInstance(new Locale(tr_TR)) 谁使用什么分隔符见en.wikipedia.org/w/…【参考方案2】:您可以使用它(法语语言环境有 ,
用于小数分隔符)
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 ",这不是我想要的。所以谢谢! 另一件事是,西班牙语言环境未列为“默认”,我无法使用new Locale("es", "ES")
构造正确格式的Locale
,然后使用NumberFormat
自动解析数字字符串,使用@ 987654329@ 作为小数分隔符,.
作为千位分隔符。只有 DecimalFormat
有效。
为什么不是所有国家都可用?我对使用法语语言环境来格式化波兰数字感到很奇怪......【参考方案3】:
正如 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();
【讨论】:
这个策略在这里详细解释:ibm.com/developerworks/library/j-numberformat【参考方案4】:Double.parseDouble(p.replace(',','.'))
... 非常快,因为它逐个字符地搜索底层字符数组。字符串替换版本编译一个正则表达式来评估。
基本上 replace(char,char) 大约快 10 倍,并且由于您将在低级代码中执行此类操作,因此考虑这一点是有意义的。热点优化器无法解决...我的系统上肯定没有。
【讨论】:
【参考方案5】:如果您不知道正确的语言环境并且字符串可以有千位分隔符,这可能是最后的手段:
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”之类的字符串。
【讨论】:
【参考方案6】:这是我在自己的代码中使用的静态方法:
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://***.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;
【讨论】:
如果默认语言环境是德语,逗号表示小数位怎么办?您可以传入,例如“1,000,000”,它不会解析为德语区域设置,然后将被替换为“1.000.000”,它不是有效的 Double。 嗨@jimmycar,我刚刚更新了我的答案以使用我的静态方法的当前版本。我希望这能解决你的问题!皮特【参考方案7】:在 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()
简单且通用!
【讨论】:
【参考方案8】:您当然需要使用正确的语言环境。 This 问题会有所帮助。
【讨论】:
【参考方案9】:如果您不知道接收到的字符串值的语言环境,并且它不一定与当前默认语言环境相同,您可以使用:
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);
无论字符串的语言环境是什么,它都会返回一个双精度值。无论有多少逗号或点。因此,通过1,000,000.54
将起作用,1.000.000,54
也将起作用,因此您不必再依赖默认语言环境来解析字符串。该代码没有尽可能优化,因此欢迎提出任何建议。我尝试测试大多数情况以确保它解决了问题,但我不确定它是否涵盖了所有情况。如果你找到一个突破值,请告诉我。
【讨论】:
【参考方案10】:这样就可以了:
Double.parseDouble(p.replace(',','.'));
【讨论】:
最初的问题说“有没有更好的方法来解析“1,234”得到1.234而不是:p = p.replaceAll(",".");",如果您认为replace
与使用replaceAll
有很大不同,请解释原因。以上是关于用逗号作为小数分隔符解析Double的最佳方法?的主要内容,如果未能解决你的问题,请参考以下文章