NumberFormat.parse()对某些货币字符串失败

时间:2013-03-23 11:15:53

标签: java android currency numberformatexception

我有一个简单的EditText,允许用户输入一个数字,例如45.60(例如美元)。然后我使用以下方法格式化此数字:

public String format() {
    NumberFormat formatter = NumberFormat.getCurrencyInstance(Locale.getDefault());
    return formatter.format(amount.doubleValue());
}

在我的Android手机上,语言设置为英语(美国) - 因此Locale.getDefault()应该返回美国语言环境(确实如此)。

现在编辑文本已正确更新为:$45.60(因此格式化输入的数字有效)。

但是,如果我尝试使用以下方法解析上面的字符串"$45.60"

NumberFormat numberFormat = NumberFormat.getInstance(Locale.getDefault());
Number result = numberFormat.parse("$45.60");

失败了:

java.lang.IllegalArgumentException: Failed to parse amount $45.60 using locale en_US.

如果我将手机设置为英语/英国,则将此"45.60"格式设置为"£45.60"可正常工作(对于美国),但解析"£45.60"会失败,就像上面的那样美国样本。

但是,如果我将手机设置为德语(德国),则将"45,60"格式设置为"45,60€"可正常工作,并且解析"45,60€"也能正常工作!

我看到这三种货币之间的唯一区别:欧元附加在金额上,而美元和英镑则附加在金额上。

有没有人有一个想法,为什么相同的代码适用于欧元,但不适用于英镑和美元?我错过了什么吗?

我还创建了一个单元测试,以重现问题:

public void testCreateStringBased() throws Exception {

    // For German locale
    CurrencyAmount amount = new CurrencyAmount("25,46€", Locale.GERMANY);
    assertEquals(25.46, amount.getAsDouble());

    // For French locale
    amount = new CurrencyAmount("25,46€", Locale.FRANCE);
    assertEquals(25.46, amount.getAsDouble());

    // For US locale
    amount = new CurrencyAmount("$25.46", Locale.US);
    assertEquals(25.46, amount.getAsDouble());

    // For UK locale
    amount = new CurrencyAmount("£25.46", Locale.UK);
    assertEquals(25.46, amount.getAsDouble());
}

CurrencyAmount基本上包装了我发布的用于解析货币字符串的代码,除了它采用给定的语言环境而不是默认的语言环境。在上面的示例中,测试在德国和法国区域设置成功,但在美国和英国区域设置失败。

6 个答案:

答案 0 :(得分:4)

由于迄今为止所提出的答案并没有完全解决问题,我采取了一种痛苦的业余方法:

String value = "$24,76" 
value = value.replace(getCurrencySymbol(locale), StringUtils.EMPTY);

NumberFormat numberFormat = NumberFormat.getInstance(locale);
Number result = numberFormat.parse(value);

所以现在我只是将String值从它的货币符号中删除......这样我可以处理我想要的所有内容,例如:45.78或45,78或$ 45.78或45,78€......

无论输入什么,货币符号都会被剥离,我最终会得到普通数字。我的单元测试(参见OP)现已成功完成。

如果有人想出更好的东西,请告诉我。

答案 1 :(得分:3)

请尝试以下操作:

NumberFormat numberFormat = new DecimalFormat("¤#.00", new DecimalFormatSymbols(Locale.UK));
numberFormat.parse("£123.5678");

¤ - 货币符号,期望与Locale匹配货币符号。

您可以通过以下链接http://docs.oracle.com/javase/6/docs/api/java/text/DecimalFormat.html

查看其他模式符号

答案 2 :(得分:1)

尝试使用NumberFormat.getCurrencyInstance()。parse()而不是NumberFormat.getInstance()。parse()。

答案 3 :(得分:0)

您必须知道要解析的字符串的语言环境才能拥有可识别语言环境的解析器。只有当NumberFormat的区域设置为en_GB时,GBP字符串才会解析为数字;没有"通用"解析器。

例如,字符串" 12.000"解析?对于我们来说,答案是十二;对于de-de,答案是一万二千。

始终使用NumberFormat.getCurrencyInstance(java.util.Locale)来解析货币金额。

答案 4 :(得分:0)

我使用以下改编自https://dzone.com/articles/currency-format-validation-and

request.getParameter("url");

response.getWriter().print(responseText);

如果您需要确保每个用户都使用正确的Locale,请查看 Change locale on login

答案 5 :(得分:0)

对不起,但提供的所有答案都具有误导性。这就是我所说的Java中的BUG。 这样的例子可以更好地说明这一点。如果我想使用EURLocale.US中打印一个值,然后再次解析,除非我在DecimalFormat上指定货币(EUR),否则它将失败。使用美元,它可以工作:

        DecimalFormat df = new DecimalFormat("¤#,##0.00", new DecimalFormatSymbols(Locale.US));
        df.setCurrency(Currency.getInstance("EUR"));
        BigDecimal value = new BigDecimal("1.23");
        String text = df.format(value);
        System.out.println(text);

        DecimalFormat df2 = new DecimalFormat("¤#,##0.00", new DecimalFormatSymbols(Locale.US));
        df2.setParseBigDecimal(true);
        BigDecimal parsed = (BigDecimal) df2.parse(text);

        BigDecimalAsserts.assertBigDecimalEquals("parsed value is the same of the original", value, parsed);