Java DecimalFormat 在执行指数符号时会产生错误

Posted

技术标签:

【中文标题】Java DecimalFormat 在执行指数符号时会产生错误【英文标题】:Java DecimalFormat creates error when enforcing exponent sign 【发布时间】:2010-08-06 14:36:38 【问题描述】:

在 Java 中,我试图让 DecimalFormat 在指数符号上强制执行符号。当它是积极的我需要一个加号出现。从我所读到的内容来看,这似乎很简单,但对我自己来说,它总是会引发错误。我很欣赏可能有其他方法可以实现我的目标,但我想了解为什么在这种特定方法中会发生错误。

Double result = 123.456;
String sresult;

//This works
NumberFormat formatter = new DecimalFormat("0.00000E00");
        sresult = formatter.format(result); 
        System.out.println(sresult);        //1.23456E02

//This doesn't work
formatter = new DecimalFormat("0.00000E+00"); //Want to enforce the sign to appear
        sresult = formatter.format(result); 
        System.out.println(sresult);        //Expected 1.23456E+02 but error occurs

抛出的错误:

线程“主”java.lang.IllegalArgumentException 中的异常: 畸形指数模式“0.00000E+00” 在 java.text.DecimalFormat.applyPattern(未知来源) 在 java.text.DecimalFormat.(未知来源) 在 deccheck.main(deccheck.java:13)

我感谢任何见解。 谢谢, 标记

【问题讨论】:

重新格式化的代码;如果不正确,请恢复。 【参考方案1】:

我想通过j flemm 扩展解决方案。 “E”和“-”不是常数,可以设置为DecimalFormatSymbols。因此,替换必须尊重这一点:

public static String hoola(final String s, final DecimalFormatSymbols symbols) 
    String result;
    final String expo = symbols.getExponentSeparator();
    final char minus = symbols.getMinusSign();
    if (!s.contains(expo + minus))  // don't blast a negative sign
    result = s.replace(expo, expo + '+');
     else result=s;
    return result;


/**
 * @param args
 */
public static void main(final String[] args) 
    final DecimalFormat decForm = (DecimalFormat) NumberFormat
            .getInstance(Locale.GERMAN);
    final DecimalFormatSymbols newSymbols = new DecimalFormatSymbols(
            Locale.GERMAN);
    newSymbols.setExponentSeparator("*10^");
    newSymbols.setMinusSign('\u2212');
    decForm.setDecimalFormatSymbols(newSymbols);
    decForm.applyPattern("0.00000E00");
    System.out.println(hoola(decForm.format(1234.567), decForm
            .getDecimalFormatSymbols()));
    System.out.println(hoola(decForm.format(000.00567), decForm
            .getDecimalFormatSymbols()));

结果是:

1,23457*10^+03 5,67000*10^-03

【讨论】:

是的,“坏”模式会破坏这段代码。实现所需行为的一种安全方法是实现自己的 NumberFormat 扩展,例如。 我喜欢。不妨也从DecimalFormatSymbols 中拉出hoola(..) 中的+ 符号。 @j flemm:我想要,但如果我正确解释 javadocs,+ 是不可更改的。 好点。我也刚注意到。这是有道理的,因为DecimalFormat 不使用+。它可能在其他本地化常量类之一中。【参考方案2】:

简单的方法:

formatter = new DecimalFormat("0.00000E00"); // Want to enforce the sign to appear
sresult = formatter.format(result);
if (!sresult.contains("E-"))  //don't blast a negative sign
    sresult = sresult.replace("E", "E+");

System.out.println(sresult);

为您的示例输出1.23456E+02

但我不相信有办法从DecimalFormat 模式中做到这一点。或者至少 javadoc 没有表明有一个。

编辑:trashgod 提出了一个很好的观点。如果您打算将其本地化到不同的地区,您可能希望从 DecimalFormatSymbols 获得积极和消极的信号。

编辑 2: Andrei 指出E 也是一个本地化变量。展示了我对本地化的了解。

【讨论】:

在本地化的情况下,也应该使用 DecimalFormatSymbols.getExponentSeparator() 中的 E。这样做的问题是,你不能真正直接使用它们,而不检查是否应该在正则表达式中转义它们(你需要额外检查它是否是一个特殊字符)。 @Andrei:+1 是的,我也忘记了。【参考方案3】:

我不认为“+”字符是模式中可接受的字符(在研究了 javadocs 之后)。指数部分 si 的模式描述为:

 Exponent:
         E MinimumExponent
 MinimumExponent:
         0 MinimumExponent(opt)

如果你在那里添加任何东西,它会混淆解析器。 我认为你唯一的选择是给它正常的模式(没有'+'),然后获取字符串并使用正则表达式在那里添加'+'。

sresult = formatter.format(result);
sresult = sresult.replaceAll("E([^\\-]+)", "E+$1");

最好的选择可能是扩展 DecimalFormat 并在覆盖格式方法中执行此操作

【讨论】:

【参考方案4】:

@j flemm 的方法很吸引人,因为“负指数使用本地化减号格式化,而不是模式的前缀和后缀。”—DecimalFormat

【讨论】:

谢谢大家。我感谢所有的cmets。我认为 javadocs 确实提到了使用 + 号的能力,但我对这个链接上提供的信息感到困惑:docjar.com/docs/api/java/text/DecimalFormat.html 我将按照 j flemm 的建议实施简单的方法,因为本地化不应该影响我。跨度> @Mark:它看起来像 Apache Harmony harmony.apache.org 的一个特性。请务必在您的代码中记录潜在的本地化问题。

以上是关于Java DecimalFormat 在执行指数符号时会产生错误的主要内容,如果未能解决你的问题,请参考以下文章

java中 DecimalFormat格式的定义

java中实现千位分割符

DecimalFormat用法

Java DecimalFormat 在格式化双精度时失去精度

DecimalFormat(数字格式)

Java数字处理类