Я работаю над CodingBat для класса и не могу понять, почему мой код не работает. Он проходит все перечисленные тесты, но не проходит «другие тесты». Если бы вы могли помочь мне понять, что не так, это было бы очень полезно. Вот проблема: Учитывая строку, подсчитайте количество слов, оканчивающихся на «y» или «z», так что учитываются «y» в «heavy» и «z» в «fez», но не «y» в «желтом». (нечувствительный к регистру). Мы будем говорить, что буква y или z стоит в конце слова, если сразу за ней не следует буква алфавита. (Примечание: Character.isLetter(char) проверяет, является ли char буквой алфавита.)
Вот тесты, которые он перечислил, и я прошел.
countYZ("fez day")
countYZ("day fez")
countYZ("day fyyyz")
countYZ("day yak")
countYZ("day:yak")
countYZ("!!day--yaz!!")
countYZ("yak zak")
countYZ("DAY abc XYZ")
countYZ("aaz yyz my")
countYZ("y2bz")
countYZ("zxyx")
Вот код, который у меня есть до сих пор. (Я знаю, что мог бы сделать это чище, преобразовав в нижний регистр, но я понял это только потом.)
public int countYZ(String str) {
int count = 0;
str = str.toLowerCase();
for (int i=0; i<str.length()-1; i++) {
if (!Character.isLetter(str.charAt(i)) && i>0 && (str.substring(i-1,i).equals("y") || str.substring(i-1,i).equals("z")))
{ count++; }
}
if (str.endsWith("y") || str.endsWith("z")) { count++; }
return count;
}
Какие "другие тесты" проваливаются?
Если я правильно помню из codingbat, «другие тесты» — это категория тестов, которые не раскрываются. Я бы проверил крайние случаи, чтобы увидеть, сможете ли вы найти тот, который не проходит
По крайней мере, включите пройденные тесты, возможно, кто-то может предоставить вам взамен неудовлетворительный тест, который поможет вам работать над тем, что у вас есть дальше.
хорошо countYZ(null) выглядит как кандидат.
Вы пробовали тестировать пустую строку? Прямо сейчас вы не проверяете, поэтому str.substring(i-1) будет исключением за пределами допустимого диапазона.
Я не могу читать эти длинные строки -> ошибка




Проблема: Как вы настроили свою логику, ваш цикл просматривает до одного символа до конца String, а затем вы проверяете последний символ с помощью вашего оператора if. тем не мение, ваш цикл эффективно проверяет только символ перед i, поэтому вы не проверяете символ. String, на котором это не сработает:
"y z "
(Обратите внимание на дополнительный пробел в конце. Это может быть любой другой небуквенный символ, который определяется как окончание предшествующего слова)
Этот String должен возвращать 2, но возвращает 1. Легко исправить это, изменив цикл на:
for (int i=0; i<str.length(); i++)
Возможно, лучший подход:
Прямо сейчас у вас есть куча логических условий, чтобы узнать, является ли символ перед ним не буквенным, является ли символ на i буквенным и так далее. На вашем месте я бы просто использовал toLower(), а потом разбил бы на любые небуквенные символы. Затем для каждого String в разделенном массиве используйте функцию endsWith, чтобы легко проверить, заканчивается ли он на z или y. Вот одно из возможных решений:
public int countYZ(String str) {
if (str == null) return 0;
str = str.toLowerCase();
int count = 0;
for(String s : str.split("[^a-z]")) {
if (s.endsWith("y") || s.endsWith("z")) {
count++;
}
}
return count;
}
Или java 8+ вы можете просто сделать:
public int countYZ(String str) {
if (str == null) return 0;
return (int)Arrays.stream(str.toLowerCase().split("[^a-z]"))
.filter(e -> e.endsWith("y") || e.endsWith("z"))
.count();
}
Который решает весь тестовый пример:

Но это все равно технически не работает для нулевых строк.
Очистка вашего кода облегчит чтение и отладку.
Не повторяйтесь! Каждый раз, когда вы пишете один и тот же фрагмент кода, вы создаете потенциальные ошибки из-за простых опечаток. Вместо этого вы можете переместить все проверки в один метод и использовать equalsIgnoreCase, чтобы проверить, соответствует ли данный символ Y или Z:
public static boolean isYOrZ(String s) {
if (s.equalsIgnoreCase("y") || s.equalsIgnoreCase("z")) return true;
else return false;
}
Прямо сейчас ваш код не работает для нулевых строк и для пустых строк, поэтому добавьте проверку перед выполнением какой-либо обработки:
int count = 0;
if (str == null || str.length() == 0) //check null first or you will get NPE!
return count;
Наконец, вы можете обновить свой код с помощью созданного вами нового вспомогательного метода. Если вы понимаете, как работает регулярное выражение, проще использовать String.split() для обработки ваших слов:
public static int countYZ(String str) {
int count = 0;
if (str == null || str.length() == 0) {
return count;
}
String[] words = str.split("[^A-z]"); //"not an alphabetic letter immediately following it"
for(String word : words) {
if (word.length() > 0) { //sanity check
if (isYOrZ(word.substring(word.length()-1))) {
++count;
}
}
}
return count;
}
Теперь вы можете тестировать, писать столько странных тестов, сколько сможете придумать. Например, огромная строка пробелов, пустая строка и т. д. Вот некоторые из них, которые я пробовал:
System.out.println(countYZ("heavY yummy TASTY yellow zed buzz"));
System.out.println(countYZ(""));
System.out.println(countYZ(null));
System.out.println(countYZ("fiZz yay"));
System.out.println(countYZ("zzzZZza yyy"));
System.out.println(countYZ("z"));
System.out.println(countYZ(" "));
System.out.println(countYZ("heavy&testy@!@#BuzZ")); //3
Который дает:
4
0
0
2
1
1
0
3
Пожалуйста, предоставьте входные данные, где вы терпите неудачу, ожидаемый результат и фактический результат.