2013-03-23 47 views
5

Tôi có một đơn giản EditText, cho phép người dùng nhập một số như 45.60 (ví dụ cho Đô la Mỹ). sau đó tôi định dạng con số này bằng cách sử dụng phương pháp sau đây:NumberFormat.parse() không thành công cho một số chuỗi tiền tệ

public String format() { 
    NumberFormat formatter = NumberFormat.getCurrencyInstance(Locale.getDefault()); 
    return formatter.format(amount.doubleValue()); 
} 

Và trên điện thoại Android của tôi, ngôn ngữ được thiết lập để tiếng Anh (Hoa Kỳ) - vì thế Locale.getDefault() nên trả lại locale Mỹ (và nó).

Bây giờ văn bản chỉnh sửa được cập nhật chính xác thành: $45.60 (do đó định dạng số đã nhập hoạt động).

Tuy nhiên, nếu tôi cố gắng để phân tích các chuỗi trên "$45.60" bằng cách sử dụng phương pháp sau đây:

NumberFormat numberFormat = NumberFormat.getInstance(Locale.getDefault()); 
Number result = numberFormat.parse("$45.60"); 

Nó không thành công với:

java.lang.IllegalArgumentException: Failed to parse amount $45.60 using locale en_US. 

Nếu tôi đặt điện thoại của tôi sang tiếng Anh/Anh, định dạng "45.60" này để "£45.60" hoạt động chính xác (như đối với Hoa Kỳ), tuy nhiên phân tích cú pháp "£45.60" không thành công, giống như đối với mẫu ở trên ở Hoa Kỳ.

Tuy nhiên, nếu tôi đặt điện thoại sang tiếng Đức (Đức), định dạng "45,60" thành "45,60€" hoạt động chính xác và phân tích cú pháp "45,60€" hoạt động chính xác!

Sự khác biệt duy nhất tôi thấy giữa ba loại tiền tệ sau: Đồng Euro được cộng vào số tiền, trong khi Đô la và Bảng Anh được thêm vào số tiền đó.

Có ai có ý tưởng không, tại sao cùng một mã hoạt động cho Euro, nhưng không phải cho Bảng Anh và Đô la? Tui bỏ lỡ điều gì vậy?

Tôi cũng đã tạo ra một đơn vị kiểm tra, để tạo lại vấn đề:

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 về cơ bản kết thúc tốt đẹp mã tôi gửi cho phân tích chuỗi tiền tệ, ngoại trừ việc nó mất miền địa phương được thay cho miền địa phương mặc định. Trong ví dụ trên, thử nghiệm thành công cho miền địa phương GERMANY và PHÁP nhưng không thành công cho miền địa phương Hoa Kỳ và Anh.

Trả lời

2

Kể từ khi câu trả lời đã được đề nghị vậy, đến nay, đã không hoàn toàn giải quyết được vấn đề, tôi sử dụng phương pháp đau đớn nghiệp dư:

String value = "$24,76" 
value = value.replace(getCurrencySymbol(locale), StringUtils.EMPTY); 

NumberFormat numberFormat = NumberFormat.getInstance(locale); 
Number result = numberFormat.parse(value); 

Vì vậy, bây giờ tôi chỉ cần bỏ giá trị String ra khỏi biểu tượng tiền tệ của nó ... Bằng cách này tôi có thể xử lý mọi thứ tôi muốn, chẳng hạn như: 45.78 hoặc 45.78 hoặc $ 45.78 hoặc 45.78 € ....

Bất kể đầu vào, ký hiệu tiền tệ chỉ đơn giản là bị tước bỏ và tôi kết thúc bằng số đơn giản. Các unittests của tôi (xem OP) bây giờ đã hoàn tất thành công.

Nếu có ai đó nghĩ ra điều gì đó tốt hơn, vui lòng cho tôi biết.

+0

Tôi sẽ không gọi nó là 'nghiệp dư đau đớn'. Đó là một trường hợp sử dụng phổ biến, đặc biệt là khi phân tích cú pháp đầu vào của EditText. Tôi cũng xem xét thực thi đúng định dạng (w/ký hiệu tiền tệ) trực tiếp trên EditText (bằng cách sử dụng TextWatcher), nhưng tôi kết thúc bằng cách sử dụng giải pháp này là ít xâm nhập cho người dùng. Cảm ơn. – pkk

1

Hãy thử NumberFormat.getCurrencyInstance(). Parse() thay cho NumberFormat.getInstance(). Parse().

+0

Ok đã thử nó và nó không thực sự làm việc. Tôi cần để có thể phân tích $ 45,65 cũng như 45,65 với cùng một mã. Nếu tôi thay đổi mã của mình như bạn đã đề xuất, việc phân tích chuỗi số (không có Ký hiệu tiền tệ) không còn hoạt động nữa. Và: sau những thay đổi đó tôi có thể phân tích $ 45.56 nhưng 45.56 € không còn hoạt động nữa ... – AgentKnopf

+1

Đây là giới hạn của các thói quen phân tích cú pháp Java. Đối với các yêu cầu cụ thể của bạn, bạn nên thử cả hai. –

+1

Cảm ơn bạn đã làm rõ. Tuy nhiên trong trường hợp đó, tôi nghĩ rằng tôi tốt hơn với thay thế đơn giản của tôi của biểu tượng tiền tệ :) - bởi vì đây là một điều, mà làm việc cho mỗi và mọi trường hợp. Và tôi thấy nó hơi cồng kềnh, nếu tôi cần hai cách tiếp cận khác nhau để làm điều tương tự (phân tích một chuỗi tiền tệ), chỉ vì một số loại tiền tệ có biểu tượng tiền tệ được thêm vào, trong khi các loại tiền tệ khác có thêm: /. Về mặt logic, nó phải đơn giản: Một thói quen cho mọi loại phân tích tiền tệ. Vì nó là ngôn ngữ dựa trên, nên không có vấn đề, nhưng thật đáng buồn nó không phải là đơn giản. – AgentKnopf

2

Hãy thử sau:

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

¤ - dấu hiệu tiền tệ, hy vọng trận đấu với ký hiệu tiền tệ theo vị trí.

những biểu tượng mẫu khác mà bạn có thể nhìn thấy bằng cách nhấp vào liên kết http://docs.oracle.com/javase/6/docs/api/java/text/DecimalFormat.html

+1

Cảm ơn đề xuất, nó hoạt động cho Dollar và Pounds, nhưng nó không hoạt động cho Euro. Tôi nghi ngờ, bởi vì trong trường hợp Euro ký hiệu tiền tệ được thêm vào, không được thêm vào? Tôi đang tìm kiếm một cái gì đó hoạt động phổ quát. Điều duy nhất tôi có thể đưa ra là dải ký hiệu tiền tệ bằng cách sử dụng regex và phân tích giá trị:/nhưng tôi muốn tránh điều đó ... – AgentKnopf

+0

một cách tiếp cận khác: Giá trị chuỗi = "123.5678 €" .replace (new DecimalFormatSymbols (Locale.GERMANY) .getCurrencySymbol(), ""); BigDecimal bigDecimal = new BigDecimal (giá trị); giúp bạn không quan tâm đến biểu tượng tiền tệ hiện tại – mokshino

+0

Xin chào, cảm ơn đề xuất đó, đó là những gì tôi đã đăng ngày hôm qua;) (xem câu trả lời của riêng tôi bên dưới) và đó là cách tôi đang làm ngay bây giờ. – AgentKnopf

0

Bạn phải biết ngôn ngữ của chuỗi mà bạn muốn phân tích cú pháp để có trình phân tích cú pháp nhận biết ngôn ngữ. Chuỗi phân tích cú pháp GBP thành CHỈ số khi miền địa phương của NumberFormat là en_GB; không có thứ như một trình phân tích cú pháp "phổ quát".

Ví dụ: cách phân tích chuỗi "12.000" chuỗi? Đối với chúng tôi, câu trả lời là mười hai; cho de-de, câu trả lời là mười hai nghìn.

Luôn sử dụng NumberFormat.getCurrencyInstance (java.util.Locale) để phân tích số tiền tệ.

0

Tôi đang sử dụng dưới đây chuyển thể từ 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)"); 
} 

Nếu bạn cần phải đảm bảo các Locale đúng đang được sử dụng cho mỗi người dùng nhìn vào Change locale on login

Các vấn đề liên quan