2009-03-30 18 views
32

Mis porcentajes se truncan con la función java.text.MessageFormat predeterminada, ¿cómo formatea un porcentaje sin perder precisión?Cómo formatear un porcentaje fraccional con java.text.MessageFormat

Ejemplo:

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; 

Respuesta

47

se ve así:

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

... está trabajando.

EDITAR: Para ver cómo se interpretan los # 'sy%' s, consulte el javadoc de java.text.DecimalFormat.

EDIT 2: Y, sí, es seguro para la internacionalización. El punto en la cadena de formato se interpreta como un separador decimal, no como un punto codificado. :-)

+0

+1, esto es mucho más fácil que lo que hice. –

+0

Sin embargo, podría no ser seguro para la internacionalización. No estoy seguro –

+0

Siempre existe el peligro de que los localizadores rompan algunas cadenas de formato, pero de lo contrario no puedo pensar en ninguna otra preocupación ... –

5

¿Qué tal

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

El formato de carbón '#' no imprime un 0 como ausente. Entonces 12.5 -> "12.5", 12.0 -> "12", no "12.0". Por supuesto, puede configurar su formateador con, p. "###, ###. ##", el lugar de los centésimos solo aparecerá si necesitas la precisión.

3

Usted se da cuenta de que "expectedResult == actualResult" siempre será falso, ¿verdad?

De todos modos, la mejor solución que puedo encontrar es configurar el formateador de forma explícita. Este es el código que probé:

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"; 
+0

hah, yeah. Lo siento por eso. Corregí el ejemplo. – Lorin

48

Creo que la forma correcta de hacerlo es la siguiente:

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

También toma en cuenta la internalización. Por ejemplo, en mi máquina con locale húngara obtuve "12,5%" como se esperaba. Inicializando percentFormat como NumberFormat.getPercentInstance(Locale.US) da "12.5%" por supuesto.

+1

¡En Android, funciona como un hechizo! Gracias. – Rainbowbreeze

2

Si la internacionalización es una preocupación: número

// 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)); 

El porcentaje formateador añade un espacio y el signo de porcentaje a la producción en los lugares que conozco. No sé si la posición del signo de porcentaje está antes de los dígitos en otras configuraciones regionales (por ejemplo, configuraciones de derecha a izquierda).

2

Mi solución hace que el mayor número de dígitos fraccionarios como escala fue en establecer un número determinado. Unidad probada con muchos tipos primitivos y 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))); 
} 
Cuestiones relacionadas