[英]NumberFormat.parse() fails for some currency strings
I have a simple EditText
, which allows the user to enter a number such as 45.60
(example for American Dollar).我有一个简单的
EditText
,它允许用户输入一个数字,例如45.60
(例如美元)。 I then format this number using the following method:然后我使用以下方法格式化这个数字:
public String format() {
NumberFormat formatter = NumberFormat.getCurrencyInstance(Locale.getDefault());
return formatter.format(amount.doubleValue());
}
And on my Android phone, the language is set to English (United States) - hence the Locale.getDefault()
should return the US locale (and it does).在我的 Android 手机上,语言设置为英语(美国) - 因此
Locale.getDefault()
应该返回美国语言环境(确实如此)。
Now the edit text is correctly updated to: $45.60
(hence formatting the entered number works).现在编辑文本正确更新为:
$45.60
(因此格式化输入的数字有效)。
However if I attempt to parse the above String "$45.60"
using the following method:但是,如果我尝试使用以下方法解析上述字符串
"$45.60"
:
NumberFormat numberFormat = NumberFormat.getInstance(Locale.getDefault());
Number result = numberFormat.parse("$45.60");
It fails with:它失败了:
java.lang.IllegalArgumentException: Failed to parse amount $45.60 using locale en_US.
If I set my phone to English/ UK, formatting this "45.60"
to "£45.60"
works correctly (as for US), however parsing "£45.60"
fails, just as it does for the above US sample.如果我将手机设置为英语/英国,则将此
"45.60"
格式化为"£45.60"
可以正常工作(对于美国而言),但是解析"£45.60"
失败,就像上面的美国样本一样。
However, if I set my phone to German (Germany), formatting "45,60"
to "45,60€"
works correctly, AND parsing "45,60€"
works correctly as well!但是,如果我将手机设置为德语(德国),将
"45,60"
格式化为"45,60€"
可以正常工作,并且解析"45,60€"
可以正常工作!
The only difference I see between those three currencies: The Euro is appended to the amount, while the Dollar and the Pound are prepended to the amount.我看到这三种货币之间的唯一区别:欧元附加到金额,而美元和英镑附加到金额。
Does anyone have an idea, why the same code works for Euro, but not for Pound and Dollar?有谁知道为什么相同的代码适用于欧元,但不适用于英镑和美元? Am I missing something?
我错过了什么吗?
I also created a unit test, to reproduce the issue:我还创建了一个单元测试,以重现该问题:
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
basically wraps the code I posted for parsing currency strings, except that it takes the given locale instead of the default locale. CurrencyAmount
基本上包装了我发布的用于解析货币字符串的代码,除了它采用给定的语言环境而不是默认语言环境。 In the above example, the test succeeds for the GERMANY and FRANCE locale but fails for US and UK locale.在上面的示例中,针对 GERMANY 和 FRANCE 语言环境的测试成功,但针对美国和英国语言环境的测试失败。
Since the answers that have been suggested thus far, did not completely solve the problem, I took a painfully amateurish approach:由于到目前为止提出的答案并没有完全解决问题,我采取了一种痛苦的业余方法:
String value = "$24,76"
value = value.replace(getCurrencySymbol(locale), StringUtils.EMPTY);
NumberFormat numberFormat = NumberFormat.getInstance(locale);
Number result = numberFormat.parse(value);
So now I simply strip the String value off it's currency symbol... This way I can process everything I want, such as: 45.78 or 45,78 or $45.78 or 45,78€ ....所以现在我只是从它的货币符号中去除字符串值......这样我可以处理我想要的一切,例如:45.78 或 45,78 或 $45.78 或 45,78€ ....
Whatever the input, the currency symbol is simply stripped and I end up with the plain number.无论输入什么,货币符号都会被简单地剥离,最后得到纯数字。 My unittests (see OP) now complete successfully.
我的单元测试(见 OP)现在成功完成。
If anyone comes up with something better, please let me know.如果有人想出更好的东西,请告诉我。
Try following:尝试以下操作:
NumberFormat numberFormat = new DecimalFormat("¤#.00", new DecimalFormatSymbols(Locale.UK));
numberFormat.parse("£123.5678");
¤ - currency sign, expects matches with currency symbol by Locale. ¤ - 货币符号,期望与 Locale 的货币符号匹配。
other pattern symbols you can see by following link http://docs.oracle.com/javase/6/docs/api/java/text/DecimalFormat.html您可以通过以下链接看到其他模式符号http://docs.oracle.com/javase/6/docs/api/java/text/DecimalFormat.html
尝试 NumberFormat.getCurrencyInstance().parse() 而不是 NumberFormat.getInstance().parse()。
You must know the locale of the string you wish to parse in order to have a locale-aware parser.您必须知道要解析的字符串的语言环境,才能使用语言环境感知解析器。 The GBP string parse to a numeric ONLY when the NumberFormat's locale is en_GB;
仅当 NumberFormat 的语言环境为 en_GB 时,GBP 字符串才会解析为数字; there is no such thing as a "universal" parser.
没有“通用”解析器这样的东西。
For example, how does the string "12.000" parse?例如,字符串“12.000”如何解析? For en-us, the answer is twelve;
对于 en-us,答案是十二; for de-de, the answer is twelve-thousand.
对于德德,答案是一万二千。
Always use NumberFormat.getCurrencyInstance( java.util.Locale ) to parse currency amounts.始终使用 NumberFormat.getCurrencyInstance( java.util.Locale ) 来解析货币金额。
I'm using below adapted from https://dzone.com/articles/currency-format-validation-and我正在使用以下改编自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)");
}
If you need to insure the correct Locale is being used per user look at Change locale on login如果您需要确保每个用户使用正确的区域设置,请查看登录时更改区域设置
Sorry, but any answer provided are misleading.抱歉,但提供的任何答案都具有误导性。 This is what I would call a BUG in Java.
这就是我所说的 Java 中的 BUG。 An example like this explains it better.
像这样的例子更好地解释了它。 If I want to print a value in
EUR
using Locale.US
and then I parse it again, it fails unless I specify on the DecimalFormat
the currency ( EUR
).如果我想使用
Locale.US
以EUR
打印一个值,然后我再次解析它,除非我在DecimalFormat
上指定货币( EUR
),否则它会失败。 Using dollars, it works:使用美元,它的工作原理:
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);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.