NumberFormat 不会因 2 个小数分隔符而崩溃

Posted

技术标签:

【中文标题】NumberFormat 不会因 2 个小数分隔符而崩溃【英文标题】:NumberFormat doesn't crash with 2 decimal separators 【发布时间】:2017-03-03 17:03:49 【问题描述】:

我对@9​​87654321@ 的行为有疑问:

当我想将格式化的String 转换/解析为Number 时,我想使用NumberFormat,因为它为我提供了千位和小数分隔符的不错预设。此外,如果提供的String 不是有效的Number,我希望它崩溃。

一个例子:

// works as expected
String testInput1 = "3,1415";
NumberFormat germanNumberFormat = NumberFormat.getInstance(Locale.GERMANY);
Number number1 = germanNumberFormat.parse(testInput1);
System.out.println(number1); // prints 3.1415

// does not work as expected, cuts off the number after the 2nd decimal
// separator, expected it to crash with java.lang.NumberFormatException:
// multiple points
String testInput2 = "3,14,15";
Number number2 = germanNumberFormat.parse(testInput2);
System.out.println(number2); // prints 3.14

我目前使用Double.parseDouble(String s),来获得这个额外的行为:

// crashes with java.lang.NumberFormatException: multiple points
double number2WithError = Double.parseDouble(testInput2.replace(",", "."));

除了编写我自己的包装类来对例如多个小数分隔符?


另外我知道NumberFormat 的使用的parse(String source) 方法的JavaDoc 说:

从给定字符串的开头解析文本以生成一个数字。该方法可能不会使用给定字符串的整个文本。

有关数字解析的更多信息,请参阅 @link #parse(String, ParsePosition) 方法。

parse(String source, ParsePosition parsePosition):

如果可能,则返回 Long(例如,在 [Long.MIN_VALUE, Long.MAX_VALUE] 范围内且不带小数),否则返回 Double。如果设置了 IntegerOnly,将在小数点处停止(或等效项;例如,对于有理数“1 2/3”,将在 1 之后停止)。不抛出异常;如果没有对象可以解析,则索引不变!

这并没有告诉我为什么该方法会以这种方式运行。我从中得到的是,他们只能解析String 的一部分(他们显然在这里所做的)并且可能只是从开头(开始位置)开始解析,直到他们找到他们无法处理的东西。


我没有找到涵盖此问题的现有问题,因此如果已有问题,请随时关闭此帖子并链接到它。

【问题讨论】:

“为什么”是因为他们就是这样写的¯(°_o)/¯ 如果行为不符合您的需要,您需要将其包装或使用不同的解析机制。 【参考方案1】:

NumberFormat.parse(String) 的行为与 as documented 完全相同:

从给定字符串的开头解析文本以生成一个数字。 该方法可能不会使用给定字符串的整个文本。

(已添加重点)

你问:

除了编写我自己的包装类来对例如多个小数分隔符?

您不能提供一种格式,该格式会使NumberFormat.parse() 为输入抛出异常,而只有一个可以根据该格式解析的初始子字符串。但是,您可以使用NumberFormat.parse(String, ParsePosition) 来确定是否解析了整个输入,因为解析位置参数不仅用于指示方法从哪里开始,还用于方法说它停止的地方。这比实施特定格式的额外检查要好得多。示例:

ParsePosition position = new ParsePosition(0);
Number result = format.parse(input, position);

if (position.getIndex() != input.length()) 
    throw new MyException();

另外,你写:

这并没有告诉我为什么该方法会以这种方式运行。

之所以这样做,是因为有时解析输入的初始部分正是您想要做的。如图所示,您可以在更轻松的解析之上构建更严格的解析,但反过来做起来就困难得多。

【讨论】:

以上是关于NumberFormat 不会因 2 个小数分隔符而崩溃的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Android 的 NumberFormat 使用逗号作为澳大利亚的小数分隔符?

Intl.NumberFormat 0或2个小数位

NumberFormat API 说明

使用VBA为负数设置带有千位分隔符、2位小数和减号的标准数字格式?

将数字格式化为字符串-带小数和千位分隔符

在 xaml 中显示当前区域性小数分隔符