BigDecimal 具有 NextBigDecimal 行为

BigDecimal hasNextBigDecimal behavior

以下代码完全符合预期:

import java.math.BigDecimal;
import java.util.Scanner;

public class Test2 {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        BigDecimal number = new BigDecimal("0");
        System.out.print("Enter a number: ");
        try {
            number = new BigDecimal(input.next());
        }
        catch(Exception e) {
            System.out.println("Not a number.");
        }
        System.out.println(number);
    }
}

如果我删除 try catch 块并将其替换为 while 循环,如下所示,它不会执行预期的操作:

import java.math.BigDecimal;
import java.util.Scanner;

public class Test {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        System.out.print("Enter a number: ");
        while (!input.hasNextBigDecimal()) {
            System.out.print("Not a number, try again: ");
            input.next();
        }
        BigDecimal number = input.nextBigDecimal();
        System.out.println(number);
    }
}

这是我运行时的输出:java测试

C:\>java Test
Enter a number: 1,1
1.1

为什么它会接受一个逗号,却打印一个句点?

如果我运行下面的代码,它打印出来:en_ZA

import java.util.Locale;

public class Test3 {
    public static void main(String[] args) {
        System.out.println(Locale.getDefault());
    }
}

正如您在下面的 link 中看到的,我的语言环境的小数点分隔符是句点:

http://www.localeplanet.com/java/en-ZA/index.html

请指教我哪里错了。

编辑:

经过进一步调查,我发现了以下内容: https://www.sadev.co.za/content/how-correctly-format-currency-south-africa

所以语言环境在技术上确实使用了逗号。脑洞大开:)

Scanner.hasNextBigDecimal() 使用默认区域设置的分组和小数点分隔符(在您的区域设置中,分组似乎是“.”,小数点似乎是“,”)来验证下一个标记是否匹配 decimalpattern:

...
DecimalFormat df =
    (DecimalFormat)NumberFormat.getNumberInstance(locale);
DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(locale);

// These must be literalized to avoid collision with regex
// metacharacters such as dot or parenthesis
groupSeparator =   "\" + dfs.getGroupingSeparator();
decimalSeparator = "\" + dfs.getDecimalSeparator();
...

这段代码来自 Scanner class 并在初始化您的 scanner 实例时执行。然后在调用 Scanner.hasNextBigDecimal() 时使用 groupSeparatordecimalSeparator 来检查下一个标记是否与十进制格式匹配。


new BigDecimal(String) 直接使用'.'作为小数点分隔符。


因此,如果您想使用 Scanner.hasNextBigDecimal() 和“.”作为用户输入的小数点分隔符,那么你应该使用 Scanners useLocale(Locale) 方法。您的代码应如下所示:

Scanner input = new Scanner(System.in);
input.useLocale(Locale.ENGLISH);
System.out.print("Enter a number: ");
while (!input.hasNextBigDecimal()) {
    System.out.print("Not a number, try again: ");
    input.next();
}
BigDecimal number = input.nextBigDecimal();
System.out.println(number);

the program accepts a comma as valid input, but then prints a period as the decimal point.

再次在 ScannernextBigDecimal() 方法中将所有 groupSeparator 替换为 "" 并将 decimalSeparator 替换为 "." =49=]。来自 Scanner class 的一段代码是:

private String processFloatToken(String token) {
    String result = token.replaceAll(groupSeparator, "");
    if (!decimalSeparator.equals("\."))
        result = result.replaceAll(decimalSeparator, ".");

这就是它接受 , 并打印 . 的原因。