16

ヨーロッパでは、小数は「,」で区切られ、オプションの「.」を使用します'千を区切る。次の通貨値を許可します。

  • US式123,456.78表記
  • ヨーロピアンスタイル 123.456,78表記

次の正規表現 (RegexBuddy ライブラリから) を使用して、入力を検証します。オプションで 2 桁の分数とオプションの 3 桁区切り記号を使用できます。

^[+-]?[0-9]{1,3}(?:[0-9]*(?:[.,][0-9]{0,2})?|(?:,[0-9]{3})*(?:\.[0-9]{0,2})?|(?:\.[0-9]{3})*(?:,[0-9]{0,2})?)$

通貨文字列をフロートに解析したいと思います。例えば

123,456.78 は 123456.78 として保存
123.456,78 は 123456.78 として保存
123.45 は 123.45 として
保存 1.234 は 1234 として保存 12.34 は 12.34 として保存

等々...

Javaでこれを行う簡単な方法はありますか?

public float currencyToFloat(String currency) {
    // transform and return as float
}

Float の代わりに BigDecimal を使用する


素晴らしい回答をありがとうございました。float の代わりに BigDecimal を使用するようにコードを変更しました。この質問の前の部分をフロートで保持して、人々が私がやろうとしていたのと同じ間違いをするのを防ぎます。

解決


次のコードは、米国および EU の通貨を BigDecimal(String) コンストラクターによって受け入れられる文字列に変換する関数を示しています。つまり、桁区切り記号のない文字列と分数の点です。

   import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class TestUSAndEUCurrency {

    public static void main(String[] args) throws Exception {       
        test("123,456.78","123456.78");
        test("123.456,78","123456.78");
        test("123.45","123.45");
        test("1.234","1234");
        test("12","12");
        test("12.1","12.1");
        test("1.13","1.13");
        test("1.1","1.1");
        test("1,2","1.2");
        test("1","1");              
    }

    public static void test(String value, String expected_output) throws Exception {
        String output = currencyToBigDecimalFormat(value);
        if(!output.equals(expected_output)) {
            System.out.println("ERROR expected: " + expected_output + " output " + output);
        }
    }

    public static String currencyToBigDecimalFormat(String currency) throws Exception {

        if(!doesMatch(currency,"^[+-]?[0-9]{1,3}(?:[0-9]*(?:[.,][0-9]{0,2})?|(?:,[0-9]{3})*(?:\\.[0-9]{0,2})?|(?:\\.[0-9]{3})*(?:,[0-9]{0,2})?)$"))
                throw new Exception("Currency in wrong format " + currency);

        // Replace all dots with commas
        currency = currency.replaceAll("\\.", ",");

        // If fractions exist, the separator must be a .
        if(currency.length()>=3) {
            char[] chars = currency.toCharArray();
            if(chars[chars.length-2] == ',') {
                chars[chars.length-2] = '.';
            } else if(chars[chars.length-3] == ',') {
                chars[chars.length-3] = '.';
            }
            currency = new String(chars);
        }

        // Remove all commas        
        return currency.replaceAll(",", "");                
    }

    public static boolean doesMatch(String s, String pattern) {
        try {
            Pattern patt = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE);
            Matcher matcher = patt.matcher(s);
            return matcher.matches();
        } catch (RuntimeException e) {
            return false;
        }           
    }  

}
4

4 に答える 4

38

少し異なる質問に答えるには、通貨の値を表すために float 型を使用 しないでください。それはあなたをかみます。のように base-10 型を代わりに使用するか、 orBigDecimalのような整数型を使用します (値の量を表す - たとえば、米国通貨のペニー)。intlong

たとえば、123.45 などの正確な値を float として格納することはできず、その値に対する数学演算 (税率による乗算など) では、丸め誤差が発生します。

そのページの例:

float a = 8250325.12f;
float b = 4321456.31f;
float c = a + b;
System.out.println(NumberFormat.getCurrencyInstance().format(c));
// prints $12,571,782.00 (wrong)

BigDecimal a1 = new BigDecimal("8250325.12");
BigDecimal b1 = new BigDecimal("4321456.31");
BigDecimal c1 = a1.add(b1);
System.out.println(NumberFormat.getCurrencyInstance().format(c1));
// prints $12,571,781.43 (right)

お金に関しては、間違いを犯したくありません。

元の質問に関して、私はしばらく Java に触れていませんが、この種の作業を行うために正規表現から離れたいと思っています。これはお勧めです。それはあなたを助けるかもしれません。未検証; 開発者に警告します。

try {
    String string = NumberFormat.getCurrencyInstance(Locale.GERMANY)
                                            .format(123.45);
    Number number = NumberFormat.getCurrencyInstance(locale)
                                            .parse("$123.45");
    // 123.45
    if (number instanceof Long) {
       // Long value
    } else {
       // too large for long - may want to handle as error
    }
} catch (ParseException e) {
// handle
}

期待するものと一致するルールを持つロケールを探します。見つからない場合は、複数を順番に使用するか、独自のカスタム NumberFormatを作成してください。

また、ユーザーに単一の標準的な形式で値を入力するよう強制することも検討します。123.45 と 123.456 は、私の好みには似すぎているように見えますあなたのルールでは、1000 倍も異なる値になります 。

于 2009-06-08T16:48:40.180 に答える