安全string转换为BigDecimal

我正在尝试从string中读取一些BigDecimal值。 比方说,我有这个string:“1,000,000,000.999999999999999”,我想从它得到一个BigDecimal。 有什么办法呢?

首先,我不喜欢使用stringreplace(replace逗号等)的解决scheme。 我觉得应该有一些整洁的格式化工为我做这个工作。

我已经find了一个DecimalFormatter类,但是当它通过双倍的操作 – 大量的精度丢失。

那么,我该怎么做呢?

检查DecimalFormat中的setParseBigDecimal 。 有了这个setter, parse会为你返回一个BigDecimal。

 String value = "1,000,000,000.999999999999999"; BigDecimal money = new BigDecimal(value.replaceAll(",", "")); System.out.println(money); 

完整的代码来certificate不引发NumberFormatException

 import java.math.BigDecimal; public class Tester { public static void main(String[] args) { // TODO Auto-generated method stub String value = "1,000,000,000.999999999999999"; BigDecimal money = new BigDecimal(value.replaceAll(",", "")); System.out.println(money); } } 

产量

1000000000.999999999999999

以下示例代码运行良好(需要dynamic获取语言环境)

 import java.math.BigDecimal; import java.text.NumberFormat; import java.text.DecimalFormat; import java.text.ParsePosition; import java.util.Locale; class TestBigDecimal { public static void main(String[] args) { String str = "0,00"; Locale in_ID = new Locale("in","ID"); //Locale in_ID = new Locale("en","US"); DecimalFormat nf = (DecimalFormat)NumberFormat.getInstance(in_ID); nf.setParseBigDecimal(true); BigDecimal bd = (BigDecimal)nf.parse(str, new ParsePosition(0)); System.out.println("bd value : " + bd); } } 

代码可以更清洁,但这似乎是做不同的语言环境的技巧。

 import java.math.BigDecimal; import java.text.DecimalFormatSymbols; import java.util.Locale; public class Main { public static void main(String[] args) { final BigDecimal numberA; final BigDecimal numberB; numberA = stringToBigDecimal("1,000,000,000.999999999999999", Locale.CANADA); numberB = stringToBigDecimal("1.000.000.000,999999999999999", Locale.GERMANY); System.out.println(numberA); System.out.println(numberB); } private static BigDecimal stringToBigDecimal(final String formattedString, final Locale locale) { final DecimalFormatSymbols symbols; final char groupSeparatorChar; final String groupSeparator; final char decimalSeparatorChar; final String decimalSeparator; String fixedString; final BigDecimal number; symbols = new DecimalFormatSymbols(locale); groupSeparatorChar = symbols.getGroupingSeparator(); decimalSeparatorChar = symbols.getDecimalSeparator(); if(groupSeparatorChar == '.') { groupSeparator = "\\" + groupSeparatorChar; } else { groupSeparator = Character.toString(groupSeparatorChar); } if(decimalSeparatorChar == '.') { decimalSeparator = "\\" + decimalSeparatorChar; } else { decimalSeparator = Character.toString(decimalSeparatorChar); } fixedString = formattedString.replaceAll(groupSeparator , ""); fixedString = fixedString.replaceAll(decimalSeparator , "."); number = new BigDecimal(fixedString); return (number); } } 

这是我将如何做到这一点:

 public String cleanDecimalString(String input, boolean americanFormat) { if (americanFormat) return input.replaceAll(",", ""); else return input.replaceAll(".", ""); } 

显然,如果这是生产代码,那不是那么简单。

我没有看到简单地从string中删除逗号的问题。

 resultString = subjectString.replaceAll("[^.\\d]", ""); 

将从您的string中删除除数字和点以外的所有字符。

为了使它具有语言环境感知能力,您可能需要使用java.text.DecimalFormatSymbols getDecimalSeparator() 。 我不知道Java,但它可能是这样的:

 sep = getDecimalSeparator() resultString = subjectString.replaceAll("[^"+sep+"\\d]", ""); 

我需要一个解决scheme来转换一个string到一个BigDecimal而不知道语言环境和独立于语言环境。 我找不到任何标准的解决scheme,所以我写了我自己的帮手方法。 也可以帮助其他人:

更新:警告! 这个辅助方法只适用于十进制数,所以总是有小数点的数字! 否则,辅助方法可能会在1000和999999(加号/减号)之间input错误的结果。 感谢bezmax他的伟大的投入!

 /** * Converts a String to a BigDecimal. * if there is more than 1 '.', the points are interpreted as thousand-separator and will be removed for conversion * if there is more than 1 ',', the commas are interpreted as thousand-separator and will be removed for conversion * the last '.' or ',' will be interpreted as the separator for the decimal places * () or - in front or in the end will be interpreted as negative number * * @param value * @return The BigDecimal expression of the given string */ public static BigDecimal toBigDecimal(final String value) { if (value != null){ boolean negativeNumber = false; if (value.containts"(") && value.contains(")") negativeNumber = true; if (value.endsWith("-") || value.startsWith("-")) negativeNumber = true; String parsedValue = value.replaceAll("[^0-9\\,\\.], EMPTY); if (negativeNumber) parsedValue = "-" + parsedValue; int lastPointPosition = parsedValue.lastIndexOf(POINT); int lastCommaPosition = parsedValue.lastIndexOf(COMMA); //handle '1423' case, just a simple number if (lastPointPosition == -1 && lastCommaPosition == -1) return new BigDecimal(parsedValue); //handle '45.3' and '4.550.000' case, only points are in the given String if (lastPointPosition > -1 && lastCommaPosition == -1){ int firstPointPosition = parsedValue.indexOf(POINT); if (firstPointPosition != lastPointPosition) return new BigDecimal(parsedValue.replace(POINT_AS_STRING, EMPTY)); else return new BigDecimal(parsedValue); } //handle '45,3' and '4,550,000' case, only commas are in the given String if (lastPointPosition == -1 && lastCommaPosition > -1){ int firstCommaPosition = parsedValue.indexOf(COMMA); if (firstCommaPosition != lastCommaPosition) return new BigDecimal(parsedValue.replace(COMMA_AS_STRING, EMPTY)); else return new BigDecimal(parsedValue.replace(COMMA, POINT)); } //handle '2.345,04' case, points are in front of commas if (lastPointPosition < lastCommaPosition){ parsedValue = parsedValue.replace(POINT_AS_STRING, EMPTY); return new BigDecimal(parsedValue.replace(COMMA, POINT)); } //handle '2,345.04' case, commas are in front of points if (lastCommaPosition < lastPointPosition){ parsedValue = parsedValue.replace(COMMA_AS_STRING, EMPTY); return new BigDecimal(parsedValue); } throw new NumberFormatException("Unexpected number format. Cannot convert '" + value + "' to BigDecimal."); } return null; } 

当然,我已经testing了这个方法:

 @Test(dataProvider = "testBigDecimals") public void toBigDecimal_defaultLocaleTest(String stringValue, BigDecimal bigDecimalValue){ BigDecimal convertedBigDecimal = DecimalHelper.toBigDecimal(stringValue); Assert.assertEquals(convertedBigDecimal, bigDecimalValue); } @DataProvider(name = "testBigDecimals") public static Object[][] bigDecimalConvertionTestValues() { return new Object[][] { {"5", new BigDecimal(5)}, {"5,3", new BigDecimal("5.3")}, {"5.3", new BigDecimal("5.3")}, {"5.000,3", new BigDecimal("5000.3")}, {"5.000.000,3", new BigDecimal("5000000.3")}, {"5.000.000", new BigDecimal("5000000")}, {"5,000.3", new BigDecimal("5000.3")}, {"5,000,000.3", new BigDecimal("5000000.3")}, {"5,000,000", new BigDecimal("5000000")}, {"+5", new BigDecimal("5")}, {"+5,3", new BigDecimal("5.3")}, {"+5.3", new BigDecimal("5.3")}, {"+5.000,3", new BigDecimal("5000.3")}, {"+5.000.000,3", new BigDecimal("5000000.3")}, {"+5.000.000", new BigDecimal("5000000")}, {"+5,000.3", new BigDecimal("5000.3")}, {"+5,000,000.3", new BigDecimal("5000000.3")}, {"+5,000,000", new BigDecimal("5000000")}, {"-5", new BigDecimal("-5")}, {"-5,3", new BigDecimal("-5.3")}, {"-5.3", new BigDecimal("-5.3")}, {"-5.000,3", new BigDecimal("-5000.3")}, {"-5.000.000,3", new BigDecimal("-5000000.3")}, {"-5.000.000", new BigDecimal("-5000000")}, {"-5,000.3", new BigDecimal("-5000.3")}, {"-5,000,000.3", new BigDecimal("-5000000.3")}, {"-5,000,000", new BigDecimal("-5000000")}, {null, null} }; } 

老主题,但也许最简单的是使用Apache公共的NumberUtils有一个方法createBigDecimal(String value)….

我想(希望)考虑到区域设置,否则它将是无用的。

请尝试这个为我工作

 BigDecimal bd ; String value = "2000.00"; bd = new BigDecimal(value); BigDecimal currency = bd;