Проблема с разбором отрицательных чисел в Java - PullRequest
0 голосов
/ 28 сентября 2019

У меня есть строка, которую я проанализировал, и я могу разбить все необходимые элементы.Я могу принять следующие значения: "| Вы находитесь в большой темной комнате | false 1 -1 -1 2", "| Вы находитесь в темной большой комнате | false -1 0 -1 -1", "| Вы находитесь в большой комнате, очень темной | false 0 0 3 0 "," | Вы находитесь в темной комнате, очень маленькой | true 0 0 0 0 ", и я могу получить описание, значение true / false,и цифры для всех отдельных.Однако, когда я пытаюсь разобрать числа в целочисленное значение, я получаю ошибку исключения числа.

Первоначально я пытался использовать целочисленное значение roomValue и сканер roomString для полученияNextInt () в roomValue.Это ужасно не удалось.Приведенный ниже код разбивает все на части, но как только я пытаюсь присвоить целочисленное значение моего массива строк, я получаю ошибку.

        description = fullDesc.substring(1, fullDesc.indexOf("| "));
        gameRooms[roomNumber] = new Room(description);
        fullDesc = fullDesc.substring(fullDesc.indexOf("| ") + 2);

        if (fullDesc.contains("true")) 
            gameRooms[roomNumber].putGrail();
        fullDesc = fullDesc.substring(fullDesc.indexOf(" "));       
        String[] roomString = fullDesc.split(" ");
        Integer[] adjRoomNum = new Integer[roomString.length];
        for (int i = 0; i < roomString.length; i++) {
            //adjRoomNum[i] = Integer.parseInt(roomString[i]);
            //System.out.println(adjRoomNum[i]);
            System.out.println((roomString[i]));
        }

        /*
        roomValue = roomString.nextInt();
        if ((roomValue) >= 0)
            gameRooms[roomNumber].setAdjacent(0, gameRooms[Integer.valueOf(roomValue)]);
        else if ((roomValue) == -1)
            gameRooms[roomNumber].setAdjacent(0, null);
        roomString  
        roomValue = roomString.nextInt();
        if ((roomValue) >= 0)
            gameRooms[roomNumber].setAdjacent(1, gameRooms[Integer.valueOf(roomValue)]);
        else if ((roomValue) == -1)
            gameRooms[roomNumber].setAdjacent(1, null);
        roomValue = roomString.nextInt();
        if ((roomValue) >= 0)
            gameRooms[roomNumber].setAdjacent(2, gameRooms[Integer.valueOf(roomValue)]);
        else if ((roomValue) == -1)
            gameRooms[roomNumber].setAdjacent(2, null);
        roomValue = roomString.nextInt();
        if ((roomValue) >= 0)
            gameRooms[roomNumber].setAdjacent(3, gameRooms[Integer.valueOf(roomValue)]);
        else if ((roomValue) == -1)
            gameRooms[roomNumber].setAdjacent(3, null);

Я получаю следующую ошибку:

Exception in thread "main" java.lang.NumberFormatException: For input string: ""
    at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.base/java.lang.Integer.parseInt(Integer.java:662)
    at java.base/java.lang.Integer.parseInt(Integer.java:770)
    at Controller.buildRoom(Controller.java:30)
    at Game.main(Game.java:67)

вывод строки:


1
-1
-1
2

-1
0
-1
-1

0
0
3
0

0
0
0
0

То, что я хочу, это

1
-1
-1
2
-1
0
-1
-1
0
0
3
0
0
0
0
0

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

Ответы [ 3 ]

0 голосов
/ 28 сентября 2019

у вас есть пробел между минусом и первым числом, после выполнения разделения - String [] roomString = fullDesc.split ("");первая строка является пустой строкой, поэтому при синтаксическом анализе она не выполняется, следует избегать ее, либо удалив ее, либо разделив ее

if(fullDesc.startWith("")) {
//substring
}
0 голосов
/ 29 сентября 2019

Метод Integer.parseInt () будет принимать строковые представления целых значений со знаком (отрицательных), таких как "- 1024" , и преобразовывать эту строку в INT .На самом деле, он также будет принимать что-то вроде "+ 1024" .То, что он не будет преобразовывать - это пустая строка, пустая строка ("") или любая числовая строка, содержащая один или несколько буквенных символов, включая пробел.Отображаемое сообщение об ошибке указывает на то, что была предпринята попытка передать пустую строку ( "" ) через метод Integer.parseInt () .

ИМХО этохорошая идея проверить строку перед выполнением преобразования, чтобы исключить необходимость генерировать исключение или, по крайней мере, попытаться перехватить исключение и разобраться с ним.

Проверка числовой строкис использованием метода String # match () :

В этом примере используется метод String # match () вместе с регулярным выражением (RegEx) для проверки того факта, что строка, содержащаяся в элементе массива roomString [i] , действительно является строковым представлением целочисленного числового значения со знаком или без знака.Если это не так, то на консоль выводится сообщение об ошибке, и обработка продолжается со следующего элемента массива.

for (int i = 0; i < roomString.length; i++) {
    // Trim off an possible leading or trailing whitespaces.
    roomString[i] = roomString[i].trim();
    if (!roomString[i].matches("\\+?\\d+|\\-?\\d+")) {
        System.err.println("The value " + roomString[i] + " located at " + 
                           "index " + i + " can not be converted to Integer!");
        continue;  // continue processing the remaining array.
    }
    adjRoomNum[i] = Integer.parseInt(roomString[i]);
    System.out.println(adjRoomNum[i]);
    //System.out.println((roomString[i]));
}

Используемый RegEx ("\\+?\\d+|\\-?\\d+") означает следующее:

  • \\+?\\d+ Если строка начинается с буквального + символа или нет, а затем следует одна или несколько цифр от 0 до 9
  • | ИЛИ
  • \\-?\\d+" Если строка начинается с буквального символа - или нет, а затем следует одна или несколько цифр от 0 до 9.

Скорее всего, вам может не понадобиться эта часть:\\+?\\d+| и может оставить его вне выражения.

Перехват исключения NumberFormatException:

for (int i = 0; i < roomString.length; i++) {
    // Trim off an possible leading or trailing whitespaces.
    roomString[i] = roomString[i].trim(); 
    try {
        adjRoomNum[i] = Integer.parseInt(roomString[i]);
    }
    catch (NumberFormatException ex) {
        System.err.println("The value " + roomString[i] + " located at " + 
                           "index " + i + " can not be converted to Integer!");
        continue;  // continue processing the remaining array.
    }

    System.out.println(adjRoomNum[i]);
    //System.out.println((roomString[i]));
}

Как вы получили пустую строку ("") для начала?

При разборе строки на основе пробелов, особенно если в строке из пользовательского ввода всегда есть вероятность, что двойной пробел был предоставлен где-то или, в вашем случае один ведущий пробел (подробнее об этом позже).Чтобы справиться с этой дилеммой, всегда обрезайте строку с помощью метода String # trim () , чтобы удалить начальные и конечные пробелы перед разбиением этой строки.

Разбор и разбиение ваших конкретных строк:

В целом, ваш синтаксический анализ работает нормально, но вы заметите, что при выполнении этой строки кода:

fullDesc = fullDesc.substring(fullDesc.indexOf(" "));

fullDescПеременная будет содержать целочисленные значения строки с пробелом в начале и в конце, например: " 1 -1 -1 2 ".Вы не хотите этого, так как это разделится на: "", "1", "-1", "-1", "2".Ваш массив roomString будет содержать один элемент Null String из-за начального пробела, а метод Integer.parseInt () не будет обрабатывать те, которые выдают NumberFormatException ,Решение простое, просто добавьте 1 в индекс подстроки или добавьте метод trim () в конец строки кода.Измените приведенную выше строку кода следующим образом:

fullDesc = fullDesc.substring(fullDesc.indexOf(" ") + 1);

                          O R

// Covers almost all the 'just in case' situations.
fullDesc = fullDesc.substring(fullDesc.indexOf(" ")).trim(); 

Это, однако, не охватывает возможную ситуацию с двойным интервалом между значениями, когда вы хотите разбить строку, например:

    "1  -1 -1  2"

Здесь у нас есть двойной пробел между 1 и -1 и еще раз между -1 и 2. Когда эта строка разбивается на основе одного пробела (String[] roomString = "1 -1 -1 2".split(" ");), вы получите шесть элементов массива, два изэто будут пустые строки ("1", "", "-1", "-1", "", "2"), и снова метод Integer.parseInt () в конечном итоге будет выдавать NumberFormatException при обнаружении пустой строки.

Решение, не используйте " " в вашем методе разделения.Вместо этого используйте "\\s+".Это небольшое регулярное выражение указывает методу split () разбивать строку на один или несколько пробелов.

При работе со строковыми цифрами, и вы хотите проанализировать их, используя Integer.parseInt () , Double.parseDouble () или любой другой пробел в числовой строке, вызывающийхаос независимо от того, какой разделитель вы используете.Возьмите этот пример числовой строки с разделителями-запятыми (,), которую Пользователь ввел в консольное приложение:

"1, 2, 3,4,5 ,6 ,7,8 , 9 , 10"

Здесь есть четыре различные ситуации с разделителями:

1) 1, 2
2) 3,4
3) 5 ,6
4) , 9 ,

Если вы быличтобы разделить эту строку, скажем:

String[] values = "1, 2, 3,4,5 ,6 ,7,8 , 9 , 10".split(",");

Ваш массив значений будет содержать:

["1", " 2", " 3", "4", "5 ", "6 ", "7", "8 ", " 9 ", " 10"]

Все элементы массива, которые содержат пробел в них, вызовут NumberFormatException при попытке проанализировать эти элементы с помощью метода Integer.parseInt () .Решение, чтобы охватить все базы, возможно, разделить его так:

String[] values = "1, 2, 3,4,5 ,6 ,7,8 , 9 , 10".split("\\s{0,},\\s{0,}");

Что означает это регулярное выражение: "\\s{0,},\\s{0,}"?Разделить запятую, даже если до или после запятой есть 0 или более пробелов.

Ваш код может выглядеть следующим образом:

String[] gameStrings = {
    "|You're in a large dark room| false 1 -1 -1 2 ",
    "|You're in a dark large room| false -1 0 -1 -1 ",
    "|You're in a large room, very dark| false 0 0 3 0 ",
    "|You're in a dark room, very small| true 0 0 0 0 "
};

for (int s = 0; s < gameStrings.length; s++) {
    String fullDesc = gameStrings[s];
    String description = fullDesc.substring(1, fullDesc.indexOf("| "));
    gameRooms[roomNumber] = new Room(description);
    fullDesc = fullDesc.substring(fullDesc.indexOf("| ") + 2);

    if (fullDesc.contains("true")) {
        gameRooms[roomNumber].putGrail();
    }
    fullDesc = fullDesc.substring(fullDesc.indexOf(" ")).trim();
    String[] roomString = fullDesc.split("\\s+");
    Integer[] adjRoomNum = new Integer[roomString.length];

    for (int i = 0; i < roomString.length; i++) {
        if (!roomString[i].trim().matches("\\+?\\d+|\\-?\\d+")) {
            System.err.println("The value " + roomString[i] + " located at "
                    + "index " + i + " can not be converted to Integer!");
            continue; // Continue processing array elements.
        }
        adjRoomNum[i] = Integer.parseInt(roomString[i]);
        System.out.println(adjRoomNum[i]);
    }
}
0 голосов
/ 28 сентября 2019

Если ваш массив roomString содержит строки типа «1» или «-1», то вы можете выполнить следующую часть

for (int i = 0; i < roomString.length; i++) {
  if(roomString[i].charAt(0) == '-'){
    roomString[i] = roomString[i].substring(1);
    adjRoomNum[i] = Integer.parseInt(roomString[i]) * (-1);
  }else{
    adjRoomNum[i] = Integer.parseInt(roomString[i]);
  }
}
...