Java-Décimal Format.analyser le retour du double de la valeur avec le nombre de décimales spécifié

je veux pouvoir convertir une chaîne en Double avec un nombre de décimales dans une chaîne de format. Donc "###, ##0.000"devrait me donner un Double à 3 décimales.

Edit - a ajouté plus d'info à ce qui se passe

L'utilisateur entre la valeur de l'INTERFACE (qui est entrée dans une Chaîne. La règle est cette valeur est limitée à 3 décimales. Le code sous-jacent stocke la valeur dans le base de données qui est ensuite utilisé dans un calcul. Par conséquent, les décimales suivantes feront que les calculs seront légèrement hors de ce qui serait attendu.

j'ai le code suivant:

try {
        // output current locale we are running under (this happens to be "nl_BE")
        System.out.println( "Current Locale is " + Locale.getDefault().toString() );

        // number in Central European Format with a format string specified in UK format
        String numberCE = "1,234567"; // 1.234567
        String formatUK = "###,##0.000";

        // do the format
        DecimalFormat formatterUK = new DecimalFormat( formatUK );
        Double valCEWithUKFormat = formatterUK.parse( numberCE ).doubleValue();

        // I want the number to DPs in the format string!!!
        System.out.println( "CE Value     " + numberCE + " in UK format (" + formatUK + ") is "
        + valCEWithUKFormat );

    } catch( ParseException ex ) {
        System.out.println("Cannot parse number");
    }
}

la forme décimale semble ignorer la chaîne de format et me donne la chaîne complète comme un Double de 1.234567.

peut-on forcer DecimalFormat à utiliser la chaîne de format lors de l'analyse? Ai-je raté quelque chose?

Cheers,

Andez

12
demandé sur Andez 2011-01-19 20:59:11

4 réponses

DecimalFormat est utilisé pour deux distinct finalités: parsing input et formatage output. Si vous voulez faire les deux, vous devrez utiliser l'objet format deux fois.

si vous voulez prendre cette valeur et formater la sortie, en limitant le nombre de chiffres significatifs, vous devez utiliser l'objet format à nouveau. Cette fois, il utilise vos règles de formatage pour créer une chaîne de sortie à partir d'une valeur numérique:

String output = formatterUK.format(valCEWithUKFormat.doubleValue() );

Cela vous donnera la sortie de 1,235

il semble que vous vouliez que cette valeur numérique soit présentée dans le format 1.235. Pour ce faire, vous devez formater la sortie en utilisant une locale spécifique (si la vôtre utilise un format différent).

cependant , je recommande d'aborder ce problème différemment:

String text = "1,234567";
NumberFormat nf_in = NumberFormat.getNumberInstance(Locale.GERMANY);
double val = nf_in.parse(text).doubleValue();

NumberFormat nf_out = NumberFormat.getNumberInstance(Locale.UK);
nf_out.setMaximumFractionDigits(3);
String output = nf_out.format(val);

quelques notes:

  • L'analyse D'entrée doit être conservée séparer du formatage de sortie. Surtout quand vous commencez à lancer dans plusieurs endroits.
  • permettent à la bibliothèque standard de faire le levage lourd pour déterminer ce qu'est une valeur d'entrée valide pour une Locale donnée. Vous avez juste besoin de choisir un endroit approprié (j'ai choisi L'Allemagne, mais cela fonctionnerait évidemment avec d'autres). Utilisez toujours les Locales lorsque c'est possible. N'essayez pas de recréer des chaînes de formatage.
  • conservez toujours votre valeur d'entrée séparée de toute formatage de sortie. C'est à dire, si vous voulez montrer seulement trois chiffres dans la sortie, c'est très bien, mais stocker la double valeur entière de toute façon.
17
répondu robert_x44 2011-01-19 18:52:53

prenant en compte ce que vous avez dit, j'ai légèrement modifié mon code pour couvrir différents endroits. La clé était de prendre une chaîne de valeur dans un format localisé à un Double qui est arrondi sur la base de la chaîne de format.

la chaîne de format est toujours un format basé au Royaume-Uni avec les séparateurs décimaux spécifiés comme"."et mille séparateurs spécifiée ",".

j'utilise la forme décimale pour analyser initialement le format localisé basé sur un format spécifié paramètres régionaux. Cela donne un Double équivalent de la chaîne correctement. J'utilise ensuite un BigDecimal pour gérer l'arrondissement. Je peux obtenir le nombre de décimales de l'instance DecimalFormat et appeler setScale sur le BigDecimal pour effectuer l'arrondissement.

la structure de code initiale a été modifiée pour vous permettre de voir ce qui se passe dans des circonstances locales différentes merci @RD01 pour noter l'importance des autres locales.

j'ai maintenant le code suivant::

private void runTests3() {
    // output current locale we are running under
    System.out.println( "Current Locale is " + Locale.getDefault().toString() );

    // number in Central European Format with a format string specified in UK format
    String numbersInEuropeanFormatString[] = new String[] { "1.000,234567", "1,2345678", "1.222.333,234567" };
    String formatUK = "###,##0.0000";

    // output numbers using the german locale
    System.out.println("Output numbers using the German locale\n");
    for(String num : numbersInEuropeanFormatString ) {
        formatNumberAsDouble(num, formatUK, Locale.GERMAN);
    }

    // output numbers using the UK locale.  
    // this should return unexpected results as the number is in European format
    System.out.println("Output numbers using the UK locale\n");
    for(String num : numbersInEuropeanFormatString ) {
        formatNumberAsDouble(num, formatUK, Locale.UK);
    }

    // output numbers using new DecimalFormat( formatUK ) - no locale specified
    System.out.println("\n\nOutput numbers using new DecimalFormat( " + formatUK + " )\n");
    for(String num : numbersInEuropeanFormatString ) {
        formatNumberAsDouble( num, formatUK, null);
    }
}

private void formatNumberAsDouble(String value, String format, Locale locale) {


    NumberFormat formatter;
    int decimalPlaces;

    // create the formatter based on the specified locale
    if( locale != null ) {
         formatter = NumberFormat.getNumberInstance(locale);
         // creating the above number format does not take in the format string
         // so create a new one that we won't use at all just to get the
         // decimal places in it
         decimalPlaces = (new DecimalFormat(format)).getMaximumFractionDigits();
    } else {
        formatter = new DecimalFormat( format );
        decimalPlaces = formatter.getMaximumFractionDigits();
    }

    // get the result as number
    Double result = null;
    try {
        result = formatter.parse( value ).doubleValue();
    } catch( ParseException ex ) {
        // not bothered at minute
    }

    // round the Double to the precision specified in the format string


    BigDecimal bd = new BigDecimal(result );
    Double roundedValue = bd.setScale( decimalPlaces, RoundingMode.HALF_UP ).doubleValue();

    // output summary
    System.out.println("\tValue = " + value);
    System.out.println( locale == null  ? "\tLocale not specified" : "\tLocale = " + locale.toString());
    System.out.println( format == null || format.length() == 0 ? "\tFormat = Not specified" : "\tFormat = " + format);
    System.out.println("\tResult (Double) = " + result);
    System.out.println("\tRounded Result (Double) (" + decimalPlaces + "dp) = " + roundedValue);
    System.out.println("");
}

produit le résultat suivant:

Current Locale is nl_BE
Output numbers using the German locale

    Value = 1.000,234567
    Locale = de
    Format = ###,##0.0000
    Result (Double) = 1000.234567
    Rounded Result (Double) (4dp) = 1000.2346

    Value = 1,2345678
    Locale = de
    Format = ###,##0.0000
    Result (Double) = 1.2345678
    Rounded Result (Double) (4dp) = 1.2346

    Value = 1.222.333,234567
    Locale = de
    Format = ###,##0.0000
    Result (Double) = 1222333.234567
    Rounded Result (Double) (4dp) = 1222333.2346

Output numbers using the UK locale

    Value = 1.000,234567
    Locale = en_GB
    Format = ###,##0.0000
    Result (Double) = 1.0
    Rounded Result (Double) (4dp) = 1.0

    Value = 1,2345678
    Locale = en_GB
    Format = ###,##0.0000
    Result (Double) = 1.2345678E7
    Rounded Result (Double) (4dp) = 1.2345678E7

    Value = 1.222.333,234567
    Locale = en_GB
    Format = ###,##0.0000
    Result (Double) = 1.222
    Rounded Result (Double) (4dp) = 1.222



Output numbers using new DecimalFormat( ###,##0.0000 )

    Value = 1.000,234567
    Locale not specified
    Format = ###,##0.0000
    Result (Double) = 1000.234567
    Rounded Result (Double) (4dp) = 1000.2346

    Value = 1,2345678
    Locale not specified
    Format = ###,##0.0000
    Result (Double) = 1.2345678
    Rounded Result (Double) (4dp) = 1.2346

    Value = 1.222.333,234567
    Locale not specified
    Format = ###,##0.0000
    Result (Double) = 1222333.234567
    Rounded Result (Double) (4dp) = 1222333.2346
5
répondu Andez 2011-01-20 11:18:31

bien sûr que tu peux. Essayez d'exécuter ceci:

String in = "1,234567";
System.out.println(NumberFormat.getNumberFormat(new Locale("fr", "FR")).parse(in));
System.out.println(NumberFormat.getNumberFormat(new Locale("en", "GB")).parse(in));

il est clair qu'ils donnent des résultats différents, la première lecture 1.234567 et la deuxième 1234567 . Peut-être qu'il y a quelque chose qui ne va pas avec ton modèle? Quoi qu'il en soit la dernière ligne il serait le moyen préféré pour obtenir le UK format standard.

0
répondu Mark Peters 2011-01-19 18:20:04

la restriction des décimales dans DecimalFormat est vraiment destinée à être utilisée dans la méthode format() et n'a pas beaucoup d'effet dans la méthode parse() .

pour obtenir ce que vous voulez, vous avez besoin de ceci:

    try {
        // output current locale we are running under (this happens to be "nl_BE")
        System.out.println("Current Locale is " + Locale.getDefault().toString());

        // number in Central European Format with a format string specified in UK format
        String numberCE = "1,234567"; // 1.234567
        String formatUK = "###,##0.000";

        // do the format
        DecimalFormat formatterUK = new DecimalFormat(formatUK);
        Double valCEWithUKFormat = formatterUK.parse(numberCE).doubleValue();

        // first convert to UK format string
        String numberUK = formatterUK.format(valCEWithUKFormat);
        // now parse that string to a double
        valCEWithUKFormat = formatterUK.parse(numberUK).doubleValue();

        // I want the number to DPs in the format string!!!
        System.out.println("CE Value     " + numberCE + " in UK format (" + formatUK + ") is " + valCEWithUKFormat);

    } catch (ParseException ex) {
        System.out.println("Cannot parse number");
    }

vous devez d'abord obtenir le nombre comme une chaîne de format UK et puis analyser ce nombre, en utilisant le formatter UK. Vous obtenez le résultat que vous recherchez. NB, cela arrondira le nombre à 3 décimales, ne pas tronquer.

soit dit en passant, je suis un peu surpris que votre formatteur britannique puisse analyser le numéro de format CE. Vous devriez vraiment analyser le nombre original avec un analyseur de format CE.

0
répondu mluisbrown 2011-01-19 18:59:04