web-dev-qa-db-fra.com

Comment formater un pourcentage fractionnaire avec Java.text.MessageFormat

Mes pourcentages sont tronqués par la fonction Java.text.MessageFormat par défaut, comment formater un pourcentage sans perdre en précision?

Exemple:

String expectedResult = "12.5%";
double fraction = 0.125;

String actualResult = MessageFormat.format("{0,number,percent}", fraction);
assert expectedResult.equals(actualResult) : actualResult +" should be formatted as "+expectedResult;
35
Lorin

Ressemble à ça:

String actualResult = MessageFormat.format("{0,number,#.##%}", fraction);

... travaille.

EDIT: pour voir comment les # et% sont interprétés, voir le javadoc de Java.text.DecimalFormat.

EDIT 2: Et, oui, il est sûr pour l'internationalisation. Le point dans la chaîne de format est interprété comme un séparateur décimal, pas comme un point codé en dur. :-)

52
david a.

Je pense que la bonne façon de procéder est la suivante:

NumberFormat percentFormat = NumberFormat.getPercentInstance();
percentFormat.setMaximumFractionDigits(1);
String result = percentFormat.format(0.125);

Il prend également en compte l'internalisation. Par exemple, sur ma machine avec des paramètres régionaux hongrois, j'ai obtenu "12,5%" comme prévu. L'initialisation de percentFormat comme NumberFormat.getPercentInstance(Locale.US) donne bien sûr "12,5%".

52
Chei

Que diriez-vous

DecimalFormat f = new DecimalFormat( "###.#" );
System.out.println( f.format( 12.5 ) );

Le format char '#' n'imprime pas un 0 comme absent. Donc 12,5 -> "12,5", 12,0 -> "12", pas "12,0". Vous pouvez bien sûr configurer votre formateur avec par exemple "###, ###. ##", la place des centièmes n'apparaîtra que si vous avez besoin de précision.

6
Steve B.

Vous vous rendez compte que "expectedResult == actualResult" sera toujours faux, non?

Quoi qu'il en soit, la meilleure solution que je puisse trouver est de définir explicitement le formateur. Voici le code que j'ai testé:

String expectedResult = "12.5%";
double fraction = 0.125;
MessageFormat fmt = new MessageFormat("{0,number,percent}");
NumberFormat nbFmt = NumberFormat.getPercentInstance();
nbFmt.setMaximumFractionDigits(1); // or 2, or however many you need
fmt.setFormatByArgumentIndex(0, nbFmt);
String actualResult = fmt.format(new Object[] {fraction});
assert expectedResult.equals(actualResult) : actualResult +" is getting rounded off";
3
Michael Myers

Ma solution affiche autant de chiffres fractionnaires que l'échelle a été définie sur un nombre donné. Unité testée avec de nombreux types primitifs et Number.

/**
 * Formats the given Number as percentage with necessary precision.
 * This serves as a workaround for {@link NumberFormat#getPercentInstance()} which does not renders fractional
 * digits.
 *
 * @param number
 * @param locale
 *
 * @return
 */
public static String formatPercentFraction(final Number number, final Locale locale)
{
    if (number == null)
        return null;

    // get string representation with dot
    final String strNumber = NumberFormat.getNumberInstance(Locale.US).format(number.doubleValue());
    // create exact BigDecimal and convert to get scale
    final BigDecimal dNumber = new BigDecimal(strNumber).multiply(new BigDecimal(100));

    final NumberFormat percentScaleFormat = NumberFormat.getPercentInstance(locale);
    percentScaleFormat.setMaximumFractionDigits(Math.max(0, dNumber.scale()));

    // convert back for locale percent formatter
    return percentScaleFormat.format(dNumber.multiply(new BigDecimal(0.01)));
}
2
djmj

Si l'internationalisation est une préoccupation:

// get locale from somewhere. default is usually a bad idea, especially
// if running in a app server
Locale locale = Locale.getDefault();
NumberFormat fmt = NumberFormat.getPercentInstance(locale);
// the question requires 1 digit for fractional part
// therefore set both, minimum and maximum digit count
fmt.setMinimumFractionDigits(1);
fmt.setMaximumFractionDigits(1);
// set grouping, if you expect large values
// notabene: not all languages use 3 digits per group
fmt.setGroupingUsed(true);
// output the example of the original question
System.out.println(fmt.format(0.125));

Le formateur de nombres en pourcentage ajoute un espace et le signe de pourcentage à la sortie dans les paramètres régionaux que je connais. Je ne sais pas, si la position du signe de pourcentage est avant les chiffres dans d'autres paramètres régionaux (paramètres régionaux de droite à gauche par exemple).

2
rhjoerg