Conversión de cadena segura a BigDecimal

Estoy tratando de leer algunos valores BigDecimal de la cadena. Digamos que tengo esta cadena: “1,000,000,000.999999999999999” y quiero obtener un BigDecimal de ella. ¿Cuál es la manera de hacerlo?

Antes que nada, no me gustan las soluciones que usan cadenas reemplaza (reemplazando comas, etc.). Creo que debería haber algún formateador aseado para hacer ese trabajo por mí.

Encontré una clase DecimalFormatter, sin embargo, como funciona a través del doble, se pierden enormes cantidades de precisión.

Entonces, ¿cómo puedo hacerlo?

Echa un vistazo a setParseBigDecimal en DecimalFormat. Con este setter, Parse te devolverá un BigDecimal.

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

Código completo para demostrar que no se arrojó 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); } } 

Salida

1000000000.999999999999999

El siguiente código de ejemplo funciona bien (la configuración regional debe obtenerse dinámicamente)

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

El código podría ser más limpio, pero esto parece ser el truco para diferentes lugares.

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

Así es como lo haría:

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

Obviamente, si esto fuera en código de producción, no sería tan simple.

No veo ningún problema con simplemente eliminar las comas de String.

Necesitaba una solución para convertir un String en un BigDecimal sin conocer la configuración regional y ser independiente de la configuración regional. No pude encontrar ninguna solución estándar para este problema, así que escribí mi propio método de ayuda. Puede ser que ayude a alguien más también:

Actualización: ¡Advertencia! Este método de ayuda solo funciona para números decimales, ¡por lo que los números siempre tienen un punto decimal! De lo contrario, el método auxiliar podría arrojar un resultado incorrecto para números entre 1000 y 999999 (más / menos). ¡Gracias a Bezmax por su gran contribución!

 static final String EMPTY = ""; static final String POINT = '.'; static final String COMMA = ','; static final String POINT_AS_STRING = "."; static final String COMMA_AS_STRING = ","; /** * 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; } 

Por supuesto que he probado el método:

 @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} }; } 
 resultString = subjectString.replaceAll("[^.\\d]", ""); 

eliminará todos los caracteres excepto los dígitos y el punto de su cadena.

Para que sea compatible con la configuración regional, es posible que desee utilizar getDecimalSeparator() desde java.text.DecimalFormatSymbols . No sé Java, pero podría verse así:

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

Viejo tema, pero tal vez el más fácil es usar Apache commons NumberUtils que tiene un método createBigDecimal (valor de cadena) ….

Supongo (espero) que tenga en cuenta las configuraciones regionales o de lo contrario sería inútil.

Por favor, intente esto, funciona para mí

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