Veilige String naar BigDecimal conversie

Ik probeer enkele BigDecimal-waarden uit de tekenreeks te lezen. Laten we zeggen dat ik deze string heb: “1,000,000,000,999999999999999” en ik wil er een BigDecimal uit halen. Wat is de manier om het te doen?

Allereerst hou ik niet van de oplossingen die string-vervangingen gebruiken (komma’s vervangen enz.). Ik denk dat er een nette formatter moet zijn om dat werk voor mij te doen.

Ik heb een DecimalFormatter-klasse gevonden, maar omdat deze dubbel werkt, gaan enorme hoeveelheden precisie verloren.

Dus, hoe kan ik dat doen?


Antwoord 1, autoriteit 100%

Bekijk setParseBigDecimalin DecimalFormat. Met deze setter, parseretourneert een BigDecimal voor u.


Antwoord 2, autoriteit 71%

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

Volledige codeom te bewijzen dat er geen NumberFormatExceptionwordt gegenereerd:

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

Uitvoer

1000000000.999999999999999


Antwoord 3, autoriteit 26%

De volgende voorbeeldcode werkt goed (lokaal moet dynamisch worden verkregen)

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

Antwoord 4, autoriteit 7%

De code zou schoner kunnen, maar dit lijkt de oplossing te zijn voor verschillende locaties.

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

Antwoord 5, autoriteit 3%

Hier is hoe ik het zou doen:

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

Als dit in productiecode zou gaan, zou het natuurlijk niet zo eenvoudig zijn.

Ik zie geen probleem met het simpelweg verwijderen van de komma’s uit de String.


Antwoord 6, autoriteit 3%

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

verwijdert alle tekens behalve cijfers en de punt uit je tekenreeks.

Om de locatie bewust te maken, kun je getDecimalSeparator()van java.text.DecimalFormatSymbols. Ik ken Java niet, maar het zou er zo uit kunnen zien:

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

Antwoord 7, autoriteit 3%

Ik had een oplossing nodig om een ​​string naar een BigDecimal te converteren zonder de landinstelling te kennen en onafhankelijk van de landinstelling te zijn. Ik kon geen standaardoplossing voor dit probleem vinden, dus schreef ik mijn eigen helpermethode. Misschien helpt het iemand anders ook:

Update: Waarschuwing! Deze hulpmethode werkt alleen voor decimale getallen, dus getallen die altijd een decimale punt hebben! Anders kan de helpermethode een verkeerd resultaat opleveren voor getallen tussen 1000 en 999999 (plus/min). Met dank aan bezmax voor zijn geweldige input!

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

Natuurlijk heb ik de methode getest:

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

Antwoord 8, autoriteit 2%

Oud onderwerp, maar misschien het gemakkelijkst is om Apache commons NumberUtils te gebruiken, die een methode heeft createBigDecimal (String-waarde)….

Ik denk (hoop) dat het rekening houdt met landinstellingen, anders zou het nogal nutteloos zijn.


Antwoord 9

Probeer dit, het werkt voor mij

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

Other episodes