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

Java 对于某些货币字符串,NumberFormat.parse()失败,java,android,currency,numberformatexception,Java,Android,Currency,Numberformatexception,我有一个简单的EditText,它允许用户输入一个数字,例如45.60(例如美元)。然后,我使用以下方法格式化此数字: public String format() { NumberFormat formatter = NumberFormat.getCurrencyInstance(Locale.getDefault()); return formatter.format(amount.doubleValue()); } NumberFormat numberFormat =

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

public String format() {
    NumberFormat formatter = NumberFormat.getCurrencyInstance(Locale.getDefault());
    return formatter.format(amount.doubleValue());
}
NumberFormat numberFormat = NumberFormat.getInstance(Locale.getDefault());
Number result = numberFormat.parse("$45.60");
在我的Android手机上,语言设置为英语(美国)-因此
Locale.getDefault()
应该返回美国语言环境(确实如此)

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

但是,如果我尝试使用以下方法分析上述字符串
“$45.60”

public String format() {
    NumberFormat formatter = NumberFormat.getCurrencyInstance(Locale.getDefault());
    return formatter.format(amount.doubleValue());
}
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.
如果我将手机设置为English/UK,则将此
“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
基本上包装了我发布的用于解析货币字符串的代码,只是它采用给定的语言环境而不是默认的语言环境。在上面的示例中,测试在德国和法国地区成功,但在美国和英国地区失败。

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

尝试以下操作:

NumberFormat numberFormat = new DecimalFormat("¤#.00", new DecimalFormatSymbols(Locale.UK));
numberFormat.parse("£123.5678");
-货币符号,按区域设置与货币符号匹配


您可以通过以下链接看到的其他图案符号

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

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

NumberFormat numberFormat = NumberFormat.getInstance(locale);
Number result = numberFormat.parse(value);
所以现在我只需去掉货币符号上的字符串值。。。这样我就可以处理我想要的一切,比如:45.78或45,78或45.78美元或45,78欧元

不管输入的是什么,货币符号都会被简单地去掉,最后我得到的是一个普通的数字。我的单元测试(参见OP)现在已成功完成


如果有人想出更好的方法,请告诉我。

您必须知道要解析的字符串的区域设置,才能拥有区域设置感知解析器。仅当NumberFormat的区域设置为en_GB时,GBP字符串才会解析为数字;没有“通用”解析器

例如,字符串“12.000”是如何解析的?对我们来说,答案是12;对于德德来说,答案是一万二千


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

我使用下面改编自

如果需要确保每个用户使用正确的语言环境,请查看

很抱歉,提供的任何答案都有误导性。这就是我在Java中所说的BUG。 像这样的例子更好地解释了这一点。如果我想使用
Locale.US
EUR
中打印一个值,然后再次解析它,除非我在
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);

好的,我试过了,但没有真正起作用。我需要能够解析45.65美元以及45.65美元与相同的代码。如果我按照您的建议更改代码,解析数字字符串(不带货币符号)将不再有效。而且:在这些更改之后,我可以解析45.56美元,但45,56欧元不再适用于oO…这是Java解析例程的一个限制。对于您的特殊要求,您应该尝试两种方法。感谢您的澄清。然而,在这种情况下,我认为我最好简单地替换货币符号:)——因为这是一件事,适用于每种情况。我发现这有点麻烦,如果我需要两种不同的方法来做同样的事情(解析货币字符串),仅仅因为一些货币有一个预先指定的货币符号,而另一些货币则附加了:/。从逻辑上讲,它应该很简单:每种货币解析都有一个例程。由于它是基于区域设置的,所以这应该没有问题,但遗憾的是,它并没有那么简单。感谢您的建议,它适用于美元和英镑,但不适用于欧元。我怀疑,因为在欧元的情况下,货币符号是附加的,而不是附加的?我在寻找一种通用的方法。我唯一能想到的另一件事是使用正则表达式剥离货币符号并解析值:/但是我宁愿避免……还有一种方法:String value=“123.5678€”;BigDecimal BigDecimal=新的BigDecimal(值);这有助于你不再关心当前货币符号嘿,谢谢你的建议,这与我昨天发布的内容差不多;)(见下面我自己的答案)我现在就是这样做的。我不会称之为“痛苦的业余”。这是一个常见的用例,尤其是在解析EditText的输入时。我还考虑直接在EditText(使用TextWatcher)上强制执行正确的(带货币符号)格式,但我最终使用此解决方案,因为它对用户的干扰较小。谢谢