2013-03-23 22 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