首页 文章

安全字符串到BigDecimal转换

提问于
浏览
109

我正在尝试从字符串中读取一些BigDecimal值 . 假设我有这个字符串:“1,000,000,000.999999999999999”,我希望得到一个BigDecimal . 这样做的方法是什么?

首先,我不喜欢使用字符串替换的解决方案(替换逗号等) . 我认为应该有一些整洁的格式化程序为我做这项工作 .

我找到了一个DecimalFormatter类,但是因为它运行的时间很长 - 大量的精度都会丢失 .

那么,我该怎么做呢?

9 回答

  • 3

    在DecimalFormat中查看setParseBigDecimal . 使用此setter,parse将为您返回BigDecimal .

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

    Full code 证明没有 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);
        }
    }
    

    Output

    1000000000.999999999999999

  • 0

    以下示例代码运行良好(需要动态获取区域设置)

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

    代码可能更干净,但这似乎可以解决不同的语言环境 .

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

    我是这样做的:

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

    显然,如果这是在 生产环境 代码中,那就不那么简单了 .

    我认为从String中删除逗号没有任何问题 .

  • 2

    我需要一个解决方案来将String转换为BigDecimal,而不需要知道语言环境并且与语言环境无关 . 我找不到任何标准的解决方案,所以我编写了自己的帮助方法 . 也许它可以帮助其他人:

    Update: Warning! This helper method works only for decimal numbers, so numbers which always have a decimal point! Otherwise the helper method could deliver a wrong result for numbers between 1000 and 999999 (plus/minus). Thanks to bezmax for his great 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;
        }
    

    当然我已经测试了这个方法:

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

    将从字符串中删除除数字和点之外的所有字符 .

    要使其可以识别区域设置,您可能希望使用java.text.DecimalFormatSymbols中的getDecimalSeparator() . 我不懂Java,但它看起来像这样:

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

    旧主题,但也许最简单的是使用Apache commons NumberUtils,它有一个方法createBigDecimal(String value)....

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

  • 85

    请试试这个为我工作

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

相关问题