checklist - ¿Cómo formatea un porcentaje fraccional con java.text.MessageFormat?
i18n java (6)
¿Te das 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";
Mis porcentajes se truncan con la función predeterminada java.text.MessageFormat, ¿cómo formatear un porcentaje sin perder precisión?
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;
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 tiene en cuenta la internalización. Por ejemplo, en mi máquina con locale húngara obtuve "12,5%" como se esperaba. Inicializar percentFormat como NumberFormat.getPercentInstance(Locale.US)
da "12.5%", por supuesto.
Mi solución representa tantos dígitos fraccionarios como la escala se estableció en Número dado. 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)));
}
Qué tal si
DecimalFormat f = new DecimalFormat( "###.#" );
System.out.println( f.format( 12.5 ) );
El formato char ''#'' no imprime un 0 como ausente. Entonces 12.5 -> "12.5", 12.0 -> "12", no "12.0". Por supuesto, puede configurar su formateador con, por ejemplo, "###, ###. ##", el lugar centésimo solo aparecerá si necesita la precisión.
Se ve como esto:
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. :-)
Si la internacionalización es una preocupación:
// 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 formateador de porcentaje de porcentaje agrega un espacio y el signo de porcentaje a la salida en las configuraciones regionales 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).