如何在Java中解析货币金额(美国或欧盟)浮动值 [英] How to parse a currency Amount (US or EU) to float value in Java

查看:125
本文介绍了如何在Java中解析货币金额(美国或欧盟)浮动值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在欧洲,小数位用分隔,我们使用可选的来分隔数千。我允许使用以下货币值:

In Europe decimals are separated with ',' and we use optional '.' to separate thousands. I allow currency values with:


  • 美式123,456.78表示法

  • 欧式123.456,78符号

我使用下一个正则表达式(来自RegexBuddy库)来验证输入。我允许可选的两位数分数和可选的千位分隔符。

I use the next regular expression (from RegexBuddy library) to validate the input. I allow optional two-digits fractions and optional thousands separators.

^[+-]?[0-9]{1,3}(?:[0-9]*(?:[.,][0-9]{0,2})?|(?:,[0-9]{3})*(?:\.[0-9]{0,2})?|(?:\.[0-9]{3})*(?:,[0-9]{0,2})?)$

我想将货币字符串解析为浮点数。例如

I would like to parse a currency string to a float. For example

123,456.78应存储为123456.78

123.456,78应存储为123456.78

123.45应存储为123.45

1.234应存储为1234
12.34应存储为12.34

123,456.78 should be stored as 123456.78
123.456,78 should be stored as 123456.78
123.45 should be stored as 123.45
1.234 should be stored as 1234 12.34 should be stored as 12.34

等等......

在Java中有一种简单的方法吗?

Is there an easy way to do this in Java?

public float currencyToFloat(String currency) {
    // transform and return as float
}

使用BigDecimal而不是Float

感谢大家的精彩答案。我已将我的代码更改为使用BigDecimal而不是float。我会用浮动来保留这个问题的前一部分,以防止人们犯同样的错误。

Thanks to everyone for the great answers. I have changed my code to use BigDecimal instead of float. I will keep previous part of this question with float to prevent people from doing the same mistakes I was gonna do.

解决方案

下一个代码显示了一个函数,该函数从美国和欧盟货币转换为BigDecimal(String)构造函数接受的字符串。这就是说一个没有千分隔符的字符串和一个分数点。

The next code shows a function which transforms from US and EU currency to a string accepted by BigDecimal(String) constructor. That it is to say a string with no thousand separator and a point for fractions.

   import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class TestUSAndEUCurrency {

    public static void main(String[] args) throws Exception {       
        test("123,456.78","123456.78");
        test("123.456,78","123456.78");
        test("123.45","123.45");
        test("1.234","1234");
        test("12","12");
        test("12.1","12.1");
        test("1.13","1.13");
        test("1.1","1.1");
        test("1,2","1.2");
        test("1","1");              
    }

    public static void test(String value, String expected_output) throws Exception {
        String output = currencyToBigDecimalFormat(value);
        if(!output.equals(expected_output)) {
            System.out.println("ERROR expected: " + expected_output + " output " + output);
        }
    }

    public static String currencyToBigDecimalFormat(String currency) throws Exception {

        if(!doesMatch(currency,"^[+-]?[0-9]{1,3}(?:[0-9]*(?:[.,][0-9]{0,2})?|(?:,[0-9]{3})*(?:\\.[0-9]{0,2})?|(?:\\.[0-9]{3})*(?:,[0-9]{0,2})?)$"))
                throw new Exception("Currency in wrong format " + currency);

        // Replace all dots with commas
        currency = currency.replaceAll("\\.", ",");

        // If fractions exist, the separator must be a .
        if(currency.length()>=3) {
            char[] chars = currency.toCharArray();
            if(chars[chars.length-2] == ',') {
                chars[chars.length-2] = '.';
            } else if(chars[chars.length-3] == ',') {
                chars[chars.length-3] = '.';
            }
            currency = new String(chars);
        }

        // Remove all commas        
        return currency.replaceAll(",", "");                
    }

    public static boolean doesMatch(String s, String pattern) {
        try {
            Pattern patt = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE);
            Matcher matcher = patt.matcher(s);
            return matcher.matches();
        } catch (RuntimeException e) {
            return false;
        }           
    }  

}


推荐答案

回答一个稍微不同的问题:使用浮点类型来表示货币值。 它会咬你。使用base-10类型,如 BigDecimal ,或类似 int 的整数类型long (代表您的价值量 - 例如,以美元计算的便士)。

To answer a slightly different question: don't use the float type to represent currency values. It will bite you. Use a base-10 type instead, like BigDecimal, or an integer type like int or long (representing the quantum of your value - penny, for example, in US currency).

您将无法存储确切的数据值 - 123.45,比方说,作为一个浮点数,对该值的数学运算(例如乘以税率)将产生舍入误差。

You will not be able to store an exact value - 123.45, say, as a float, and mathematical operations on that value (such as multiplication by a tax percentage) will produce rounding errors.

该页面的示例:

float a = 8250325.12f;
float b = 4321456.31f;
float c = a + b;
System.out.println(NumberFormat.getCurrencyInstance().format(c));
// prints $12,571,782.00 (wrong)

BigDecimal a1 = new BigDecimal("8250325.12");
BigDecimal b1 = new BigDecimal("4321456.31");
BigDecimal c1 = a1.add(b1);
System.out.println(NumberFormat.getCurrencyInstance().format(c1));
// prints $12,571,781.43 (right)

您不希望在发生错误时遇到错误它涉及到金钱。

You don't want to muck with errors when it comes to money.

关于原始问题,我有一段时间没有接触过Java,但我知道我想远离正则表达式做这种工作。我看到这个推荐;它可能会帮助你。未经测试;警告开发人员。

With respect to the original question, I haven't touched Java in a little while, but I know that I'd like to stay away from regex to do this kind of work. I see this recommended; it may help you. Not tested; caveat developer.

try {
    String string = NumberFormat.getCurrencyInstance(Locale.GERMANY)
                                            .format(123.45);
    Number number = NumberFormat.getCurrencyInstance(locale)
                                            .parse("$123.45");
    // 123.45
    if (number instanceof Long) {
       // Long value
    } else {
       // too large for long - may want to handle as error
    }
} catch (ParseException e) {
// handle
}

查找具有与您期望看到的规则相匹配的规则的语言环境。如果找不到,请按顺序使用多个,或创建自己的自定义NumberFormat

Look for a locale with rules that match what you expect to see. If you can't find one, use multiple sequentially, or create your own custom NumberFormat.

我还考虑强制用户以单一规范格式输入值。 123.45和123.456看起来 way 对我的口味来说太相似了,按照你的规则会导致值相差1000倍。这就是数百万人丢失的原因

I'd also consider forcing users to enter values in a single, canonical format. 123.45 and 123.456 look way too similar for my tastes, and by your rules would result in values that differ by a factor of 1000. This is how millions are lost.

这篇关于如何在Java中解析货币金额(美国或欧盟)浮动值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆