2013-03-23 24 views
5

我有一个简单的EditText,它允许用户输入一个数字,如45.60(例如美元)。然后我用下面的方法格式化这个数字:某些货币字符串的NumberFormat.parse()失败

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. 

如果我把我的电话英语/ 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基本上包裹我张贴解析货币字符串,只不过它采用给定语言环境,而不是默认语言环境的代码。在上面的示例中,德国和法国区域设置的测试成功,但美国和英国区域设置失败。

回答

2

既然已提出迄今答案看,并没有彻底解决问题

其它图案符号,我参加了一个痛苦的业余做法:

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)现在可以成功完成。

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

+0

我不会称之为'痛苦的业余'。这是一个常见的用例,尤其是在解析EditText的输入时。我也考虑直接在EditText(使用TextWatcher)上强制执行正确的(W /货币符号)格式,但是我最终使用这种解决方案对用户的干扰较小。谢谢。 – pkk 2013-12-04 09:08:14

1

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

+0

好的尝试过使用,并没有真正发挥作用。我需要能够使用相同的代码解析$ 45.65以及45.65。如果我按照您的建议更改我的代码,则解析数字字符串(不带货币符号)不再有效。并且:在这些更改之后,我可以解析45.56美元,但是45,56欧元不再适用于OO ... – AgentKnopf 2013-03-23 12:41:53

+1

这是Java解析例程的限制。对于您的特定要求,您应该尝试两种方法。 – 2013-03-23 15:58:56

+1

感谢您的澄清。然而,在那种情况下,我认为我用我简单的货币符号代替就更好了 - 因为这是一回事,它适用于每一种情况。我觉得有点麻烦,如果我需要两种不同的方法来做同样的事情(解析一个货币字符串),仅仅因为一些货币有一个预先的货币符号,而另一些货币则附加了:/。从逻辑上讲,它应该很简单:每种货币解析都有一个例程。由于它是基于语言环境的,所以这不应该成为问题,但可悲的是它并不那么简单。 – AgentKnopf 2013-03-23 21:01:19

2

尝试以下操作:

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

¤ - 货币符号,希望通过本地货币符号匹配。您可以通过以下链接http://docs.oracle.com/javase/6/docs/api/java/text/DecimalFormat.html

+1

感谢您的建议,它适用于美元和英镑,但它不适用于欧元。我怀疑,因为在欧元的情况下,货币符号是附加的,而不是前缀?我宁愿寻找普遍适用的东西。我唯一能想出的其他东西是使用正则表达式剥离货币符号并解析值:/但我宁愿避免... – AgentKnopf 2013-03-23 13:07:39

+0

一个更多的方法: String value =“123.5678€”.replace(new DecimalFormatSymbols(Locale.GERMANY).getCurrencySymbol(),“”); BigDecimal bigDecimal = new BigDecimal(value); 它是帮助你不关心当前的货币符号 – mokshino 2013-03-24 12:52:09

+0

嘿,谢谢你的建议,这几乎是我昨天发布的;)(见我自己的答案),这就是我现在正在做的。 – AgentKnopf 2013-03-24 13:34:34

0

您必须知道您希望解析的字符串的区域设置,才能使用区域识别解析器。当NumberFormat的区域设置为en_GB时,GBP字符串仅解析为数字;没有像“通用”解析器那样的东西。

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

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

0

我使用的是从以下https://dzone.com/articles/currency-format-validation-and

import java.math.BigDecimal; 
import org.apache.commons.validator.routines.*; 

BigDecimalValidator currencyValidator = CurrencyValidator.getInstance(); 
BigDecimal parsedCurrency = currencyValidator.validate(currencyString); 
if (parsedCurrency == null) { 
     throw new Exception("Invalid currency format (please also ensure it is UTF-8)"); 
} 

适应如果您需要确保正确的区域被每个用户看 Change locale on login