6

我有一个简单的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基本上包装了我发布的用于解析货币字符串的代码,除了它采用给定的语言环境而不是默认的语言环境。在上面的示例中,德国和法国语言环境的测试成功,但美国和英国语言环境的测试失败。

4

6 回答 6

7

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

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

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

于 2013-03-23T13:48:42.697 回答
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

于 2013-03-23T12:55:59.503 回答
1

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

于 2013-03-23T11:46:54.877 回答
0

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

例如,字符串“12.000”如何解析?对于 en-us,答案是十二;对于德德,答案是一万二千。

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

于 2015-05-07T21:05:49.683 回答
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)");
}

如果您需要确保每个用户使用正确的区域 设置,请查看登录时更改区域设置

于 2016-06-29T20:17:58.803 回答
0

对不起,但提供的任何答案都具有误导性。这就是我所说的 Java 中的 BUG。像这样的例子更好地解释了它。如果我想在EURusing中打印一个值,Locale.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);
于 2020-03-23T22:56:05.097 回答