Как разбить число на строки цифр?

1

Я новичок в программировании на Java, я попробовал образец кода, чтобы получить ввод двухзначного числа и напечатать формулировку этого номера.

public class ReadNumberInWord {

    public Integer number;

    public ReadNumberInWord() {
        Scanner userInput = new Scanner(System.in);
        System.out.println("Enter the number to read out : ");

        try {
            number = userInput.nextInt();
            readNumber();
        } catch (Exception e) {
            System.out.println("Please enter an integer");
            new ReadNumberInWord();
        }
    }

    public void readNumber() {
        System.out.println("Entered number is : " + number);
        int numSize = number.toString().length();
        System.out.println("number size is : " + numSize);

        switch (numSize) {
            case 1:
                sizeOne();
                break;
            case 2:
                sizeTwo();
                break;
            case 3:
                sizeThree();
                break;
            case 4:
                sizeFour();
                break;
            default:
                System.out.println("Enter number of four digit or less ");
                new ReadNumberInWord();
                break;
        }
    }

    private void sizeFour() {
        System.out.println("Number in words : " + numberCheck(number.toString()));
    }

    private void sizeThree() {
        String[] sizeThree = number.toString().split("");
        System.out.println(sizeThree[0]);
        System.out.println(sizeThree[1]);
        System.out.println(sizeThree[2]);

        for (int i = 0; i <= sizeThree.length - 1; i++) {
            System.out.println(sizeThree[i]);
        }

        System.out.println("Number in words : " + numberCheck(number.toString()));
    }

    private void sizeTwo() {
        String[] sizeTwo = number.toString().split("");
        //System.out.println(sizeTwo[0]);
        //System.out.println(sizeTwo[1]);
        String wordsString1 = "";
        ArrayList<String> wordsArray = new ArrayList<String>();
        for (int i = 0; i <= sizeTwo.length - 1; i++) {
            System.out.println(sizeTwo[i]);
            String words = numberCheck(sizeTwo[i]);
            wordsArray.add(words);
        }

        for (String w : wordsArray) {
            wordsString1 += w + "\t";
        }
        System.out.println("Number in words : " + wordsString1);
    }

    private void sizeOne() {
        System.out.println("Number in words : " + numberCheck(number.toString()));
    }

    public String numberCheck(String numb) {
        int num = Integer.parseInt(numb);
        switch (num) {
            case 0:
                return "zero";
            case 1:
                return "one";
            case 2:
                return "two";
            case 3:
                return "three";
            case 4:
                return "four";
            case 5:
                return "five";
            case 6:
                return "six";
            case 7:
                return "seven";
            case 8:
                return "eight";
            case 9:
                return "nine";
            case 10:
                return "ten";
            default:
                return "unknown";
        }
    }

    public static void main(String[] args) {
        new ReadNumberInWord();
    }
}

В приведенном выше коде, если я введу двузначное число как 78, он должен напечатать семь восемь. Но это не работает. Вместо этого я получил исключение. Пожалуйста, помогите мне исправить это.

Теги:

3 ответа

3

Трассировка стека - это очень полезные фрагменты информации при отладке, и если вы столкнулись с неожиданным исключением, но не считая трассировки стека, вы игнорируете эту информацию. Если бы вы напечатали трассировку стека для своего исключения, вы бы увидели это:

Enter the number to read out : 
78
Entered number is : 78
number size is : 2

Exception in thread "main" java.lang.NumberFormatException: For input string: ""
    at java.lang.NumberFormatException.forInputString(Unknown Source)
    at java.lang.Integer.parseInt(Unknown Source)
    at java.lang.Integer.parseInt(Unknown Source)
    at ReadNumberInWord.numberCheck(ReadNumberInWord.java:74)
    at ReadNumberInWord.sizeTwo(ReadNumberInWord.java:58)
    at ReadNumberInWord.readNumber(ReadNumberInWord.java:26)
    at ReadNumberInWord.<init>(ReadNumberInWord.java:13)
    at ReadNumberInWord.main(ReadNumberInWord.java:94)

Это ясно показывает, что Integer.parseInt(), через numberCheck(), вызывается с пустой строкой "" для ввода, которая не является допустимым целым числом и заставляет Integer.parseInt() генерировать исключение, которое вы видите.

Теперь вам нужно выяснить, почему это происходит. Вы знаете, что строка, переданная в parseInt() поступает непосредственно из параметра numberCheck(), поэтому означает, что numberCheck() передается пустой строкой. Поскольку вы знаете, что вход поступает из массива sizeTwo в sizeTwo(), хорошим началом было бы распечатать содержимое этого массива:

System.out.println(Arrays.toString(sizeTwo));

Сделав это, вы увидите:

[ , 7, 8 ]

Этот первый пустой элемент является подсказкой. Использование split таким образом не совсем корректно, технически строка ввода начинается с "пустой" строки, и вы получаете ее обратно (например, расщепление ":7:8" on :. Вам придется либо сделать numberCheck() игнорировать пустые строки, либо найти другой способ разделить строку на цифры. Первая - это бандажная помощь по первопричине проблемы (помните: это не ваше фактическое намерение включать любые пустые строки в список цифр), поэтому мы сосредоточимся на последнем.

Один из вариантов - преобразовать число в String (пропустить String[] вещь), а затем массив char, например:

char[] digits = number.toString().toCharArray();

Затем вы можете работать с char вместо String. Другой вариант - использовать substring() в вашем цикле, например:

String numberstr = number.toString();

for (int n = 0; n < numberstr.length(); ++ n) {
   String digit = number.substring(n, 1);
   ...
}

Конечно, наличие этого среднего человека на самом деле не обязательно, и вы могли бы просто сделать это с помощью арифметики:

for (int n = (int)Math.log10(number); n >= 0; -- n) {
    int digit = (number / (int)Math.pow(10, n)) % 10;
    System.out.println(digit);
}

Или наоборот, но не полагаясь на вычисления с плавающей запятой:

int temp = number;

while (temp) {
    digit = temp % 10;
    temp /= 10;
    System.out.println(digit);
}

Ваш код может быть очищен и значительно упрощен многими другими способами (например, как намекнул Ричард Мискин в комментарии, действительно ли вам нужен синтаксический int?), Но я думаю, что вышеописанное охватывает корень вашей непосредственной проблемы,


Что касается самой обработки ошибок, я рекомендую просто использовать Scanner.next() для чтения строки, тогда вы можете использовать Integer.parseInt() для ее синтаксического анализа, и если вы увидите NumberFormatException, спросите еще раз. Это будет подходящим использованием исключения, а использование next() а не nextInt() вытащит токен из потока, даже если это недопустимый int (позволяющий продолжить запрос для ввода). Например:

Scanner userInput = new Scanner(System.in);
System.out.println("Enter the number to read out : ");

while (true) {
    try {
        number = Integer.parseInt(userInput.next());
        break;
    } catch (NumberFormatException x) {     
        System.out.println("Please enter a valid integer");
    }
};

Обратите внимание на несколько ключевых концепций:

  • Самое узкое исключение можно поймать (например, NumberFormatException, а не Exception). Имеет смысл, потому что: NumberFormatException - единственная проблема, с которой мы пытаемся справиться.
  • Обработчики исключений обычно должны пытаться восстановить; иначе нет смысла обращаться с ними. В этом случае наша попытка восстановления состоит в том, чтобы уведомить пользователя о том, что что-то пошло не так, и запросить новый действительный ввод.

Ваша текущая реализация устанавливает рекурсивный стек и имеет несколько других проблем.

  • 0
    +1 Очень хороший и подробный ответ
1

Проблема заключается в следующем:

String[] sizeTwo=number.toString().split("");

когда число равно "78", оно генерирует массив ["", "7", "8"] вместо ["7", "8"]. Вы должны разделить строку на цифры по-разному (или игнорировать первый токен, который всегда является пустой строкой).

split (..) принимает регулярное выражение, которое определяет, какие шаблоны следует рассматривать как разделители токенов. В вашем случае я нашел следующее regex полезным:

String[] sizeTwo=number.toString().split("(?<=\\d)(?=\\d)");

Это требует, чтобы разделитель представлял собой пустую строку, предшествующую и сопровождаемую цифрой (с использованием функции, называемой положительным lookbehind и положительным взглядом)

1

Кажется немного странным, что вы читаете символы с терминала в виде Integer а затем должны прыгать через обручи, чтобы преобразовать его в массив символов для дальнейшей обработки. Логику можно упростить, прочитав в String, подтвердив, что String соответствует вашему требованию, а затем обрабатывает каждый символ из String.

Есть еще несколько изменений, которые я бы сделал:

  1. Нет причин рассматривать каждую длину как особый случай,
  2. Вы можете зацикливаться, а не называть конструктор снова в случае ошибок,
  3. number не должен быть переменной-членом, вы можете просто передать его как параметр для каждого вызова метода,
  4. Вам не нужно преобразовывать отдельные элементы String в целые числа для оператора switch, если вы используете toCharArray().

Вот пример, который работает со String а не с Integer.

import java.util.Scanner;

public class ReadNumberInWord {

    public ReadNumberInWord() {
        final Scanner userInput = new Scanner(System.in);
        System.out.println("Enter the number to read out : ");
        boolean success = false;
        // Keep looping until the correct input is supplied.
        while (!success) {
            final String number = userInput.nextLine();
            if (validNumber(number)) {
                readNumber(number);
                success = true;
            }
        }
    }

    /**
     * @param number
     *            the String to check.
     * @return <code>true</code> if and only if number is less than 5 characters
     *         long and can be parsed as an integer.
     */
    private boolean validNumber(final String number) {
        boolean returnValue = false;
        try {
            Integer.parseInt(number);
            if (number.length() <= 4) {
                returnValue = true;
            } else {
                System.out.println("Enter number of four digit or less ");
            }
        } catch (final NumberFormatException e) {
            System.out.println("Please enter an integer");
        }
        return returnValue;
    }

    /**
     * When supplied a String that represents an integer this method writes out
     * each digit as a word to stdout.
     * 
     * @param number
     *            a String that represents an integer
     */
    public void readNumber(final String number) {
        System.out.println("Entered number is : " + number);
        final int numSize = number.length();
        System.out.println("number size is : " + numSize);
        final char[] chars = number.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            System.out.print(numberCheck(chars[i]));
            if (i < chars.length - 1) {
                System.out.print('\t');
            } else {
                System.out.println();
            }
        }
    }

    /**
     * @param num
     *            a character that represents one of the numbers 0-9
     * @return the word representing the supplied number e.g. zero, one etc
     */
    public String numberCheck(final char num) {
        switch (num) {
        case '0':
            return "zero";
        case '1':
            return "one";
        case '2':
            return "two";
        case '3':
            return "three";
        case '4':
            return "four";
        case '5':
            return "five";
        case '6':
            return "six";
        case '7':
            return "seven";
        case '8':
            return "eight";
        case '9':
            return "nine";
        default:
            return "unknown";
        }
    }

    public static void main(final String[] args) {
        new ReadNumberInWord();
    }
}
  • 1
    +1 за решение других способов упрощения (и документирования !). Я предлагаю использовать символьные константы ('0', '1', '2') вместо кодов ASCII для удобства чтения. :)
  • 0
    Хороший вызов - я переключился на символьные константы.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню