小数点記号としてコンマを使用してparseDoubleを実行する最良の方法は?


148

次の結果になりますException

String p="1,234";
Double d=Double.valueOf(p); 
System.out.println(d);

解析するためのより良い方法がある"1,234"取得する1.234以上は:p = p.replaceAll(",",".");


17
私の経験では、あなたが提案したように、replaceAll()がこれを行う最良の方法です。現在のロケールに依存せず、シンプルで機能します。
Joonas Pulakka

1
@Marco Altieri:replaceAll(",",".")すべてのコンマをドットに置き換えます。コンマがない場合は、何もしません。Double.valueOf()小数点を小数点として使用する文字列でのみ機能します。ここでは、現在のデフォルトロケールの影響を受けません。docs.oracle.com/javase/8/docs/api/java/lang/...
Joonas Pulakka

4
唯一の問題replaceAll(",",".")は、単一のカンマがある場合にのみ機能することです。つまり、1,234,567がスローされ java.lang.NumberFormatException: multiple pointsます。肯定的な先読みを持つ正規表現で十分ですp.replaceAll(",(?=[0-9]+,)", "").replaceAll(",", ".")。詳細:regular-expressions.info/lookaround.html
artemisian

2
問題はない。NumberFormatExceptionは適切です。どのカンマが正しいものかをどのようにして知ることができますか?形式が間違っており、ユーザーに例外よりも読みやすいメッセージを表示することしかできません。
1

2
@TheincredibleJanいいえ、形式は間違っていません。一部のロケールではコンマを3桁ごとの区切り文字として使用するため、1つの数値に複数のロケールを含めることができますが、技術的には有効な入力です。
Vratislav Jindra

回答:


206

java.text.NumberFormatを使用します。

NumberFormat format = NumberFormat.getInstance(Locale.FRANCE);
Number number = format.parse("1,234");
double d = number.doubleValue();

11
これが機能するのは、現在のデフォルトロケールで、小数点としてカンマが使用されている場合のみです。
Joonas Pulakka、2010

6
さらに混乱させるために、一部のロケールでは、桁区切り記号としてカンマを使用しています。この場合、 "1,234"はエラーをスローする代わりに1234.0に解析されます。
Joonas Pulakka、2010

17
NumberFormatの問題は、無効な文字を黙って無視することです。したがって、「1,23abc」を解析しようとすると、渡された文字列に解析不可能な文字が含まれていることを通知せずに、1.23が返されます。実際には望ましいかもしれないいくつかの状況では、それは通常望ましい動作ではないと思います。
E-Riz 2013年

7
トルコのために、あなたはNumberFormat.getInstance(新しいロケール(tr_TR))を使用する必要があります
GünayGültekin

2
セパレーターを誰が使用するかについては、en.wikipedia.org
w

67

あなたはこれを使うことができます(フランスのロケールは,小数点記号のために持っています)

NumberFormat nf = NumberFormat.getInstance(Locale.FRANCE);
nf.parse(p);

またはjava.text.DecimalFormat、適切なシンボルを使用および設定できます。

DecimalFormat df = new DecimalFormat();
DecimalFormatSymbols symbols = new DecimalFormatSymbols();
symbols.setDecimalSeparator(',');
symbols.setGroupingSeparator(' ');
df.setDecimalFormatSymbols(symbols);
df.parse(p);

はい...千の区切り記号を設定せずにフランス語形式を使用した場合、スペイン語形式の数値(1.222.222,33)は「1 222 222,33」に変換されますが、これは私が望むものではありません。 。ほんとありがと!
WesternGun 2017年

1
もう一つは、スペイン語のロケールはdefault`を「と表示されていないと私は構築することができないLocaleと、正しい形式でnew Locale("es", "ES")、その後、自動的に付き数の文字列を解析NumberFormatし、,小数点としてセパレータと.千個のグループ・セパレータとしてのみ。DecimalFormat動作します。
WesternGun

なぜすべての国が利用できないのですか?ポーランド語の数値のフォーマットにフランス語ロケールを使用するのは変だと思います...
Line

18

E-Rizが指摘するように、NumberFormat.parse(String)は「1,23abc」を1.23として解析します。入力全体を取得するには、以下を使用できます。

public double parseDecimal(String input) throws ParseException{
  NumberFormat numberFormat = NumberFormat.getNumberInstance(Locale.getDefault());
  ParsePosition parsePosition = new ParsePosition(0);
  Number number = numberFormat.parse(input, parsePosition);

  if(parsePosition.getIndex() != input.length()){
    throw new ParseException("Invalid input", parsePosition.getIndex());
  }

  return number.doubleValue();
}

2
この戦略について詳しくは、ibm.com
developerworks / library / j

7
Double.parseDouble(p.replace(',','.'))

...基礎となる文字配列を文字単位で検索するので非常に高速です。文字列置換バージョンは、評価するRegExをコンパイルします。

基本的にreplace(char、char)は約10倍高速であり、低レベルのコードでこの種のことを行うので、これについて考えることは理にかなっています。ホットスポットオプティマイザーはそれを理解しません...私のシステムには確かにありません。


4

正しいロケールがわからず、文字列に1000の区切り文字を含めることができる場合は、これが最後の手段になる可能性があります。

    doubleStrIn = doubleStrIn.replaceAll("[^\\d,\\.]++", "");
    if (doubleStrIn.matches(".+\\.\\d+,\\d+$"))
        return Double.parseDouble(doubleStrIn.replaceAll("\\.", "").replaceAll(",", "."));
    if (doubleStrIn.matches(".+,\\d+\\.\\d+$"))
        return Double.parseDouble(doubleStrIn.replaceAll(",", ""));
    return Double.parseDouble(doubleStrIn.replaceAll(",", "."));

注意:これは「R 1 52.43,2」から「15243.2」までの文字列を解析します。


4

これは私が自分のコードで使用する静的メソッドです:

public static double sGetDecimalStringAnyLocaleAsDouble (String value) {

    if (value == null) {
        Log.e("CORE", "Null value!");
        return 0.0;
    }

    Locale theLocale = Locale.getDefault();
    NumberFormat numberFormat = DecimalFormat.getInstance(theLocale);
    Number theNumber;
    try {
        theNumber = numberFormat.parse(value);
        return theNumber.doubleValue();
    } catch (ParseException e) {
        // The string value might be either 99.99 or 99,99, depending on Locale.
        // We can deal with this safely, by forcing to be a point for the decimal separator, and then using Double.valueOf ...
        //http://stackoverflow.com/questions/4323599/best-way-to-parsedouble-with-comma-as-decimal-separator
        String valueWithDot = value.replaceAll(",",".");

        try {
          return Double.valueOf(valueWithDot);
        } catch (NumberFormatException e2)  {
            // This happens if we're trying (say) to parse a string that isn't a number, as though it were a number!
            // If this happens, it should only be due to application logic problems.
            // In this case, the safest thing to do is return 0, having first fired-off a log warning.
            Log.w("CORE", "Warning: Value is not a number" + value);
            return 0.0;
        }
    }
}

5
デフォルトのロケールがドイツ語のようなもので、コンマが小数点を表す場合はどうなりますか?たとえば、 "1,000,000"を渡すと、ドイツ語のロケールに解析されず、有効なDoubleではない "1.000.000"に置き換えられます。
Eddie Curtis

こんにちは、@ jimmycarです。現在のバージョンの静的メソッドを使用するように回答を更新しました。これで問題が解決することを願っています!ピート
ピート


0

受け取った文字列値のロケールがわからない場合で、現在のデフォルトロケールと同じロケールである必要がない場合は、次のように使用できます。

private static double parseDouble(String price){
    String parsedStringDouble;
    if (price.contains(",") && price.contains(".")){
        int indexOfComma = price.indexOf(",");
        int indexOfDot = price.indexOf(".");
        String beforeDigitSeparator;
        String afterDigitSeparator;
        if (indexOfComma < indexOfDot){
            String[] splittedNumber = price.split("\\.");
            beforeDigitSeparator = splittedNumber[0];
            afterDigitSeparator = splittedNumber[1];
        }
        else {
            String[] splittedNumber = price.split(",");
            beforeDigitSeparator = splittedNumber[0];
            afterDigitSeparator = splittedNumber[1];
        }
        beforeDigitSeparator = beforeDigitSeparator.replace(",", "").replace(".", "");
        parsedStringDouble = beforeDigitSeparator+"."+afterDigitSeparator;
    }
    else {
        parsedStringDouble = price.replace(",", "");
    }

    return Double.parseDouble(parsedStringDouble);

}

文字列のロケールに関係なく、doubleを返します。そして、コンマやポイントがいくつあっても。したがって、パス1,000,000.54は機能する1.000.000,54ため、文字列を解析するためにデフォルトのロケールに依存する必要がなくなります。コードは最適化されていないため、どんな提案でも歓迎します。ほとんどのケースをテストして問題が解決することを確認しようとしましたが、すべてを網羅しているとは限りません。あなたが破壊的な価値を見つけたら私に知らせてください。


-5

これは仕事をします:

Double.parseDouble(p.replace(',','.')); 

6
最初の質問は、「1,234を解析して1.234を取得するには、p = p.replaceAll( "、"、 "。");よりも良い方法はありますか」と述べました。、のreplace使用と大きく異なると思われる場合は、そのreplaceAll理由を説明してください。
SuperBiasedMan 2015
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.