#java #regex #loops #sorting
Вопрос:
Мне нужно выбрать все слова максимальной длины и все слова минимальной длины.
Например:
When I was younger, so much younger than today
I never needed anybody's help in any way
But now these days are gone, I'm not so self-assured
Now I find I've changed my mind
I've opened up the doors
Пример вывода:
Min: I, s, m
Max: younger, anybody, assured, changed
Я уже разобрался в алгоритме, но он просто завершается после цикла сортировки (с int k), и я не могу понять, почему, потому что отладчик ничего не говорит из-за моего модульного тестирования. Это просто прекращается.
Не могли бы вы помочь мне понять, почему это не работает, пожалуйста?
P.S. Я не могу использовать контейнерные классы
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Part2 {
public static void main(String[] args) {
String input = Util.getInput("part2.txt");
System.out.print(convert(input));
}
public static String convert(String input) {
Pattern p = Pattern.compile("[A-zА-я] ");
Matcher m = p.matcher(input);
int i = 0;
String[] arr = new String[100];
while (m.find()){
arr[i] = m.group(0);
i ;
}
StringBuilder longestResult = new StringBuilder();
longestResult.append("Max: ");
StringBuilder shortestResult = new StringBuilder();
shortestResult.append("Min: ");
int longest = 0;
int shortest = arr[0].length();
for (int k = 0; k < arr.length; k ){
if (arr[k].length() > longest){
longest = arr[k].length();
}
if (arr[k].length() < shortest){
shortest = arr[k].length();
}
}
for ( String word : arr) {
if (word.length() == longest) {
longestResult.append(word ", ");
}
if (word.length() == shortest) {
shortestResult.append(word ", ");
}
}
return shortestResult.substring(1, shortestResult.length() - 2)
longestResult.substring(1, longestResult.length() - 2);
}
}
Ответ №1:
Проблема, с которой вы столкнулись, довольно проста и легко отлаживается даже без отладчика. Ваш код имеет основной метод и может быть запущен выбранной вами средой разработки для отладки. Я предлагаю вам взглянуть на то, как отлаживать свой код, чтобы позже помочь вам с более сложными проблемами.
Просто взглянув на код, я вижу концептуальную проблему. Вы создаете массив строк, который частично заполняется в цикле while. Все эти элементы являются null
таковыми, если только вы не присваиваете им значение. Таким образом, первые i
элементы будут иметь набор строк, все остальные элементы будут null
. После этого вы зацикливаетесь на всем массиве ( k < arr.length
). Проблема возникает внутри этого цикла for, потому что вы пытаетесь вызвать length()
null
элементы -. arr[k].length()
вызовет исключение NullPointerException, начиная с i
-го элемента. Та же проблема возникает позже снова с word.length()
. Запуск вашего кода подтверждает вышесказанное:
Исключение в потоке «основной» java.lang.Исключение NullPointerException
на линии с. if (arr[k].length() > longest){
Один из способов исправить это (из многих) — выполнить итерацию только по элементам массива, которые на самом деле содержат значение ( 0 .. (i-1)
), например: for (int k = 0; k < (i - 1); k ){
. То же самое относится и ко второму циклу for.
Лучшим решением является использование String#split()
, которое принимает регулярное выражение, определяющее, где разделить входные данные, и возвращает вам массив напрямую. Этот массив не имеет нулевых элементов и содержит ровно столько элементов, чтобы содержать результат. Вы можете заменить свой цикл while этим и получить решение, которое работает более чем на 100 слов без жестко заданного ограничения. Если вы используете это, вам не нужно изменять свои циклы.
String[] arr = input.split("[\p{Punct}\s] ");
Дополнительные замечания:
- Используйте a
StringJoiner
вместо aStringBuilder
, чтобы иметь чистый способ получить значения, разделенные запятыми:StringJoiner longestWords = new StringJoiner(", ")
затем используйтеlongestWords.add(word)
и, наконец, сконструируйте результат"Max: " longestWords
. - Вам нужно найти способ, чтобы в результате не было повторяющихся значений.