2011-01-19 17 views
11

Quiero convertir una cadena en Doble dado un número de posiciones decimales en una cadena de formato. Entonces "###, ## 0.000" debería darme un Doble a 3 decimales.Java - Decimal Format.parse para devolver el valor doble con el número especificado de posiciones decimales

Edición - añadió más información a lo que sucede

El usuario introduce el valor en la interfaz de usuario - que es introducida en una cadena. La regla es que este valor está limitado a 3 decimales. El código subyacente almacena el valor en la base de datos que luego se usa en un cálculo. Por lo tanto, los lugares decimales finales harán que los cálculos sean ligeramente más de lo que se esperaría.

Tengo el siguiente código:

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"); 
    } 
} 

El DecimalFormat parece ignorar la cadena de formato y me da la cadena completa como doble de 1,234567.

¿Se puede obligar a DecimalFormat a utilizar la cadena de formato al analizar? ¿Me estoy perdiendo de algo?

Saludos,

Andez

+0

¿Realmente quiere tratar de hacer esto? Debido a la pérdida de precisión en la conversión de base 10 a binario (la representación interna), es posible que no obtenga lo que espera. – Raedwald

Respuesta

5

Tomando en consideración lo que ha dicho He modificado un poco mi código para cubrir diferentes configuraciones regionales. La clave estaba llevando una cadena de valor en un formato localizado a un Doble que se redondeaba en función de la cadena de formato.

La cadena de formato siempre es un formato basado en el Reino Unido con los separadores decimales especificados como "." y miles de separadores especificados como ",".

Estoy usando DecimalFormat para analizar inicialmente el formato localizado basado en una configuración regional especificada. Esto da un doble equivalente de la cadena correctamente. Luego uso un BigDecimal para manejar el redondeo. Puedo obtener el número de decimales de la instancia DecimalFormat y llamar a setScale en BigDecimal para realizar el redondeo.

La estructura del código inicial se ha modificado para permitirle ver lo que sucede en diferentes circunstancias de la configuración regional, gracias a @ RD01 para tener en cuenta la importancia de otras configuraciones regionales.

ahora tengo código como sigue:

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(""); 
} 

Esto produce el siguiente resultado:

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 
0

Claro que puedes. Pruebe a ejecutar esto:

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

Es evidente que como resultado diferentes de salida, la primera lectura y la segunda 1.2345671234567. Tal vez hay algo mal con su patrón? De todos modos, la última línea sería la forma preferida de obtener el formato estándar UK.

15

DecimalFormat se utiliza para dos distintos propósitos: entrada de análisis y salida de formato. Si desea hacer ambas cosas, deberá usar el objeto de formato dos veces.

Si desea tomar ese valor y formatear la salida, restringiendo el número de dígitos significativos, debe volver a utilizar el objeto de formato. Esta vez se utiliza sus reglas de formato para crear una cadena de salida a partir de un valor numérico:

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

Esto le dará la salida de 1,235

Parece desea que este valor numérico que se presentará en el formato 1.235 . Para hacer esto, debe formatear el resultado usando una configuración regional específica (si la suya usa un formato diferente).

Sin embargo, recomendaría abordar este problema de manera diferente:

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

Unas pocas notas:

  • análisis sintáctico de entrada debe mantenerse separado del formato de salida. Especialmente cuando comienzas a lanzar en varios Locales.
  • Permitir que la biblioteca estándar realice un gran trabajo de levantamiento para determinar el valor de entrada válido para una configuración regional determinada.Solo necesita seleccionar una configuración regional apropiada (elegí ALEMANIA, pero obviamente esto funcionaría con otros). Siempre use Locales cuando sea posible. No intente recrear cadenas de formato.
  • Siempre almacene su valor de entrada SEPARATE desde cualquier formato de salida. IE, si quiere mostrar solo tres dígitos en la salida, está bien, pero almacene todo el valor doble de todos modos.
0

La restricción de decimales en DecimalFormat sirve realmente para su uso en el método format() y no tiene mucho efecto en el método parse().

Con el fin de obtener lo que desea necesita esta:

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"); 
    } 

Primero es necesario para obtener el número como una cadena de formato Reino Unido y luego analizar ese número, usando el formateador Reino Unido. Eso te dará el resultado que estás buscando. NB, esto redondeará el número a 3 decimales, no truncará.

Por cierto, estoy un poco sorprendido de que su formateador del Reino Unido pueda analizar el número de formato CE. Realmente debería analizar el número original con un analizador de formato CE.

Cuestiones relacionadas