Pregunta

Quiero ser capaz de convertir una cadena en un doble dado un número de decimales en una cadena de formato. Así "###, ## 0.000" debería darme un doble a 3 decimales.

Editar - añadió más información de lo que ocurre

El usuario introduce el valor en la interfaz de usuario - que es introducida en una cadena. La regla es este valor se limita a 3 decimales. El código tiendas subyacentes el valor en la base de datos que luego se utiliza en un cálculo. Por lo tanto, las cifras decimales de fuga hará que los cálculos para estar fuera ligeramente a lo que cabría esperar.

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 un doble de 1,234567.

Can DecimalFormat verá obligado a utilizar la cadena de formato al analizar? Me estoy perdiendo algo?

Saludos,

Andez

¿Fue útil?

Solución 2

Teniendo en cuenta lo que ha dicho que he modificado mi código ligeramente para cubrir diferentes lugares. La clave estaba tomando una cadena de valor en un formato localizada a un doble que es redondeada sobre la base de la cadena de formato.

El formato de cadena es siempre un formato basado en el Reino Unido con decimales separadores especifican como "" y mil separadores especifican como "".

Estoy utilizando el DecimalFormat para analizar inicialmente el formato localizada en base a una configuración regional especificada. Esto da un equivalente doble de la cadena correctamente. Luego utilizo un BigDecimal para manejar el redondeo. Puedo obtener el número de decimales de la instancia DecimalFormat y setScale llamada en el BigDecimal para realizar el redondeo.

La estructura del código inicial se ha modificado para que pueda ver lo que sucede en diferentes circunstancias de localización gracias @ RD01 para anotar importancia de otros lugares.

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

Otros consejos

DecimalFormat se utiliza para dos distintas propósitos: análisis sintáctico de entrada y el formato de salida. Si desea hacer las dos cosas, que tendrá que utilizar el objeto de formato de dos veces.

Si usted quiere tomar ese valor y dar formato a la salida, la restricción del número de dígitos significativos, es necesario utilizar el objeto de formato nuevo. 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 ello, se debe formatear la salida utilizando una configuración regional específica (si el suyo utiliza 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);

Algunas notas:

  • análisis sintáctico de entrada debe mantenerse separado de formateo de salida. Especialmente cuando se inicia lanzando en varios entornos locales.
  • Permita que la biblioteca estándar para hacer el trabajo pesado para determinar lo que es un valor de entrada es válida para una determinada configuración regional. Sólo tiene que seleccionar una configuración regional apropiada (elegí ALEMANIA, pero esto, obviamente, el trabajo con los demás). Utilice siempre existen variantes regionales cuando sea posible. No trate de recrear el formato de cadenas.
  • Guarde siempre su valor de entrada separada de cualquier formato a la salida. IE, si desea mostrar solamente tres dígitos en la salida, que está muy bien, pero almacenar todo el valor doble de todos modos.

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 conseguir lo que quieres que necesita esto:

    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. Que les permite conocer el resultado que busca. NB, esto va a redondear el número de 3 cifras decimales, no trunca.

Por cierto, estoy un poco sorprendido de que el formateador Reino Unido es capaz de analizar el número de formato de la CE. Que realmente debería estar analizando el número original con un analizador de formato de la CE.

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

Está claro que como resultado diferentes de salida, el primero 1.234567 lectura y la segunda 1234567. Tal vez hay algo mal con su patrón? De todos modos la última línea no sería la mejor forma de conseguir el UK formato estándar.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top