Mam prosty EditText
, który pozwala użytkownikowi wprowadzić numer, taki jak 45.60
(przykład dla amerykańskiego dolara). I następnie sformatować ten numer przy użyciu następującej metody:Funkcja NumberFormat.parse() kończy działanie dla niektórych łańcuchów walutowych
public String format() {
NumberFormat formatter = NumberFormat.getCurrencyInstance(Locale.getDefault());
return formatter.format(amount.doubleValue());
}
I na moim telefonie z systemem Android, język jest ustawiony na angielski (Stany Zjednoczone) - stąd Locale.getDefault()
powinien zwrócić locale nas (i to robi).
Teraz tekst edycji jest poprawnie aktualizowany do: $45.60
(dlatego formatowanie wprowadzonej liczby działa).
Jednakże jeśli próbuję analizować powyższy ciąg "$45.60"
stosując następujące metody:
NumberFormat numberFormat = NumberFormat.getInstance(Locale.getDefault());
Number result = numberFormat.parse("$45.60");
nie jest on z:
java.lang.IllegalArgumentException: Failed to parse amount $45.60 using locale en_US.
Jeżeli ustawić swój telefon na angielski/UK, formatowanie to "45.60"
do "£45.60"
działa poprawnie (jak w USA), jednak parsowanie "£45.60"
kończy się niepowodzeniem, podobnie jak w przypadku powyższej próbki USA.
Jeśli jednak ustawię mój telefon na niemiecki (Niemcy), formatowanie "45,60"
na "45,60€"
działa poprawnie, I parsowanie "45,60€"
działa również poprawnie!
Jedyna różnica między tymi trzema walutami: euro jest doliczane do kwoty, a dolara i funta są dodawane do kwoty.
Czy ktoś ma pomysł, dlaczego ten sam kod działa dla euro, ale nie dla funta i dolara? Czy czegoś brakuje?
Stworzyłem również testów jednostkowych, aby odtworzyć problem:
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
zasadzie otacza kod napisałem do parsowania ciągów walut, z wyjątkiem, że zajmuje daną locale zamiast domyślnego ustawienia regionalne. W powyższym przykładzie test kończy się niepowodzeniem dla ustawień regionalnych NIEMCY i FRANCJA, ale kończy się niepowodzeniem w przypadku ustawień regionalnych w USA i Wielkiej Brytanii.
Nie nazwałbym tego "boleśnie amatorskim". Jest to typowy przypadek użycia, szczególnie podczas analizowania danych wejściowych EditText. Zastanawiałem się również nad wymuszaniem poprawnego formatu (w/znak waluty) bezpośrednio w EditText (przy użyciu TextWatchera), ale w końcu używam tego rozwiązania jako mniej uciążliwego dla użytkownika. Dzięki. – pkk