Java – Decimal Format.parse返回具有指定小数位数的double值

我希望能够在格式字符串中给定多个小数位的情况下将字符串转换为Double 。 所以“###,## 0.000”应该给我一个2到3的小数位。

编辑 – 为发生的事情添加了更多信息

用户在UI中输入值 – 输入到String中。 规则是此值限制为3位小数。 底层代码将值存储在数据库中,然后在计算中使用。 因此,尾随小数位将导致计算略微超出预期。

我有以下代码:

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

DecimalFormat似乎忽略了格式字符串,并给我完整的字符串作为1.234567的Double

DecimalFormat在解析时是否可以强制使用格式字符串? 我错过了什么吗?

干杯,

Andez

DecimalFormat用于两个不同的目的:解析输入和格式输出。 如果要同时执行这两项操作,则必须使用格式对象两次。

如果要获取该值并格式化输出,限制有效位数,则需要再次使用format对象。 这次它使用您的格式规则从数值创建输出字符串:

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

这将为您提供1,235的输出

您似乎希望此数值以1.235格式显示。 为此,您应该使用特定的区域设置格式化输出(如果您使用不同的格式)。

但是 ,我建议不同地处理这个问题:

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

几点说明:

  • 输入解析应与输出格式分开。 特别是当你开始投掷多个Locales时。
  • 允许标准库执行繁重的工作以确定给定Locale的有效输入值。 你只需要选择一个合适的Locale(我选择了德国,但这显然适用于其他人)。 始终尽可能使用Locales。 不要尝试重新创建格式字符串。
  • 始终将输入值SEPARATE存储在任何输出格式中。 IE,如果你想在输出中只显示三位数,那很好,但无论如何都要保存整个双值。

接受你所说的我稍微修改了我的代码以涵盖不同的语言环境。 关键是将本地化格式的值字符串转换为基于格式字符串舍入的Double。

格式字符串始终是基于英国的格式,小数分隔符指定为“。”。 和千个分隔符指定为“,”。

我使用DecimalFormat来初始解析基于指定语言环境的本地化格式。 这样可以正确地给出一个Double等价的字符串。 然后我使用BigDecimal来处理舍入。 我可以从DecimalFormat实例获取小数位数,并在BigDecimal上调用setScale来执行舍入。

初始代码结构已经过修改,允许您查看在不同语言环境下发生的情况,感谢@ RD01,以了解其他语言环境的重要性。

我现在的代码如下:

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

这会产生以下输出:

 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 

你当然可以。 试试这个:

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

显然它们会产生不同的输出,第一个读数为1.234567 ,第二个读数为1234567 。 也许你的模式有问题? 无论如何,最后一行将是获得UK标准格式的首选方式。

DecimalFormat中小数位的限制实际上是用于format()方法,并且在parse()方法中没有太大作用。

为了得到你想要的东西,你需要这个:

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

首先需要将数字作为英国格式字符串,然后使用英国格式化程序解析该数字。 这将为您提供您正在寻找的结果。 注意,这会将数字四舍五入到小数点后3位,而不是截断。

顺便说一句,我有点惊讶你的英国格式化程序能够解析CE格式编号。 你真的应该使用CE格式解析器解析原始数字。