Строковый индекс вне диапазона: 22 исключение Java

#java #string #exception #indexoutofboundsexception

Вопрос:

Я продолжаю получать строковый индекс из-за исключения bound: 22. Кто-нибудь может сказать мне, что я делаю не так? Вот код:

 class Troll {
    private static final char[] VOWELS = {'a', 'A', 'e', 'E', 'i', 'I', 'o', 'O', 'u', 'U'};

    public static String disemvowel(String str) {
        int lengthStr = str.length();
        int lengthVOWELS = VOWELS.length;

        for (int i = 0; i < lengthStr;   i)
            for (char vowel : VOWELS)
                if (str.charAt(i) == vowel)
                    str = removeChar(str, i);

        return str;
    }

    private static String removeChar(String str, int index) {
        return str.substring(0, index)   str.substring(index   1);
    }
}
 

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

Ответ №1:

Когда вы делаете строку короче, вы уменьшаете ее длину. Но вы сохраняете начальную длину строки и используете ее в качестве привязки цикла.

Измените i < lengthStr на i < str.length() .


Это устраняет часть проблемы, которая заключается IndexOfOfBoundsException в том, что . Другая проблема заключается в том, что, удалив символ, вам нужно убедиться, что вы также полностью проверили следующий символ.

Рассмотрим строку aa :

  • Вы бы нашли a в позиции 0 и удалили ее.
  • Следующий a теперь находится в позиции 0; вы бы пропустили проверку, является ли это гласной
  • Затем вы перейдете на контрольную позицию 1.

Это сработало бы, если бы вы строили гласные в порядке проверки (например aeiou ), но не в целом.

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

     for (int i = 0; i < lengthStr;   i) {
        for (char vowel : VOWELS) {
            if (str.charAt(i) == vowel) {
                str = removeChar(str, i);
                // Decrement i, so it gets incremented back to the
                // same value on the next iteration of the outer loop.
                --i;
                break;  // Break out of vowels loop.
            }
        }
    }
 

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

Если вы хотите сделать это без регулярных выражений, лучший способ-создать a StringBuilder и добавлять в него только не гласные:

 StringBuilder sb = new StringBuilder(lengthStr);
for (int i = 0; i < lengthStr;   i) {
  char c = str.charAt(i);
  if (!isVowel(c) {
    sb.append(c);
  }
}
str = sb.toString();
 

где isVowel метод, который возвращает, является ли данное char гласным, например

 boolean isVowel(char c) {
  return "aAeEiIoOuU".indexOf(c) >= 0;
}
 

Комментарии:

1. Прежде чем я прочитал вторую часть вашего ответа, я реорганизовал код, как вы сказали здесь, за исключением того, что я использовал i = 0 вместо —i. Но теперь я вижу, что не было необходимости снова перебирать всю строку. Спасибо вам за быстрый ответ.

Ответ №2:

Попробуй это.

 private static final String VOWELS = "aAeEiIoOuU";

public static String disemvowel(String str) {
    return Stream.of(str.split(""))
        .filter(c -> !VOWELS.contains(c))
        .collect(Collectors.joining());
}
 

Ответ №3:

     public static String disemvowel(String str) {
        return str.replaceAll("[aeiou]", "");
    }
 

это то, что тебе нужно. Если вам также нужен верхний регистр, используйте "[aeiouAEIOU]" тогда. Это сделает результирующую строку всего за один проход через исходную строку.