Странное поведение со сканером # nextFloat

Выполнение следующего в Eclipse изначально заставило Scanner не распознавать возврат каретки в консоли, эффективно блокируя дальнейший ввод:

price = sc.nextFloat();

Добавление этой строки перед кодом заставляет сканер принимать 0,23 (французская нотация) как float:

Locale.setDefault(Locale.US);

Это, скорее всего, связано с региональными настройками в Windows XP Pro (французский/бельгийский). Когда код снова запускается, 0,23 все еще принимается, а ввод 0.23 заставляет его бросать java.util.InputMismatchException.

Любое объяснение того, почему это происходит? Также есть обходной путь или я должен просто использовать Float#parseFloat?

Изменить: это демонстрирует, как сканер ведет себя с разными языками (раскомментируйте одну из строк в начале).

import java.util.Locale;
import java.util.Scanner;


public class NexFloatTest {

    public static void main(String[] args) {

        //Locale.setDefault(Locale.US);
        //Locale.setDefault(Locale.FRANCE);

        // Gives fr_BE on this system
        System.out.println(Locale.getDefault());

        float price;

        String uSDecimal = "0.23";
        String frenchDecimal = "0,23";

        Scanner sc = new Scanner(uSDecimal);

        try{
            price = sc.nextFloat();
            System.out.println(price);
        } catch (java.util.InputMismatchException e){
            e.printStackTrace();
        }

        try{
            sc = new Scanner(frenchDecimal);
            price = sc.nextFloat();
            System.out.println(price);
        } catch (java.util.InputMismatchException e){
            e.printStackTrace();
        }

        System.out.println("Switching Scanner to System.in");

        try{
            sc = new Scanner(System.in);
            System.out.println("Enter a float value");
            price = sc.nextFloat();
            System.out.println(price);
        } catch (java.util.InputMismatchException e){
            e.printStackTrace();
        }

        System.out.print("Enter title:");

        String title = sc.nextLine(); // This line is skipped

        System.out.print(title);
    }

}

Изменить: это воспроизводит проблему, в которой сканер ожидает значения с плавающей точкой, но не сработает при нажатии return:

import java.util.Scanner;

public class IgnoreCRTest {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("Enter a float value:");
        // On french Locale use , as the decimal separator
        float testFloat = sc.nextFloat();
        System.out.println(testFloat);
        //sc.skip("\n"); // This doesn't solve the issue
        sc.nextLine();
        System.out.println("Enter an integer value:");
        int testInt = sc.nextInt();
        System.out.println(testInt);
        // Will either block or skip here
        System.out.println("Enter a string value :");
        String testString = sc.nextLine();
        System.out.println(testString);
    }

}

Ответы

Ответ 1

Интересно, правильно ли вы обрабатываете маркер конца строки. Часто, если вы используете Scanner # next ###() (за исключением nextLine), и вы достигаете маркера конца строки, как когда пользователь нажимает кнопку ввода, если вы не обрабатываете маркер конца строки, это предотвратит сканер объект от работы соответствующим образом. Чтобы решить эту проблему, вызовите сканер # nextLine(), когда нужно использовать этот токен. Если вы разместите часть своего кода, мы увидим, действительно ли это ваша проблема, и если мое предложение предлагает решение.

edit: нет, вы не используете System.in, так что это не проблема. С другой стороны, вам нужно установить языковой стандарт сканера, прежде чем принимать французский номер. то есть.,

     sc = new Scanner(frenchDecimal);
     sc.useLocale(Locale.FRENCH);
     price = sc.nextFloat();