Подтвердить что ты не робот

Как проверить, содержит ли строка все буквы алфавита?

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

К сожалению, код вызывает ошибку IndexOutOfBoundsException внутри условия if, где я удаляю элементы из arraylist

List<Character> alphabets = new ArrayList<Character>();

alphabets.add('a');
alphabets.add('b');
alphabets.add('c');
alphabets.add('d');
alphabets.add('e');
alphabets.add('f');
alphabets.add('g');
alphabets.add('h');
alphabets.add('i');
alphabets.add('j');
alphabets.add('k');
alphabets.add('l');
alphabets.add('m');
alphabets.add('n');
alphabets.add('o');
alphabets.add('p');
alphabets.add('q');
alphabets.add('r');
alphabets.add('s');
alphabets.add('t');
alphabets.add('u');
alphabets.add('v');
alphabets.add('w');
alphabets.add('x');
alphabets.add('y');
alphabets.add('z');

// This is the string- I've just put a random example
String str = "a dog is running crazily on the ground who doesn't care about the world";

//Remove all the spaces
str = str.replace(" ", "");

// Convert the string to character array
char[] strChar = str.toCharArray();

for (int i = 0; i < strChar.length; i++) {

    char inp = strChar[i];

    if (alphabets.contains(inp)) {
        alphabets.remove(inp);
    }
}

if (alphabets.isEmpty())
    System.out.println("String contains all alphabets");
else
    System.out.println("String DOESN'T contains all alphabets");
4b9b3361

Ответ 1

Кажется, что все эти решения проделывают большую работу для относительно простой проверки, особенно с учетом потокового API Java 8:

/* Your lowercase string */.chars()
    .filter(i -> i >= 'a' && i <= 'z')
    .distinct().count() == 26;

Изменение: для скорости

Если вы хотите завершить итерацию строки, как только будет найден весь алфавит, все еще используя потоки, вы можете отслеживать HashSet внутри:

Set<Integer> chars = new HashSet<>();
String s = /* Your lowercase string */;
s.length() > 25 && s.chars()
    .filter(i -> i >= 'a' && i <= 'z') //only alphabet
    .filter(chars::add) //add to our tracking set if we reach this point
    .filter(i -> chars.size() == 26) //filter the 26th letter found
    .findAny().isPresent(); //if the 26th is found, return

Таким образом, поток прекратится, как только Set заполнится 26 необходимыми символами.

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

Ответ 2

List.remove удаляется по индексу. Поскольку a char может быть применено к int, вы эффективно удаляете индексы, которые не существуют, т.е. char 'a' равно int 97. Как вы видите, ваш список не содержит 97 записей.

Вы можете сделать alphabet.remove(alphabets.indexOf(inp));

Как указано @Scary Wombat (fooobar.com/questions/418762/...) и @Kevin Esche (fooobar.com/questions/418762/...), есть более эффективная альтернатива вашему алгоритму

Ответ 3

Regex - ваш друг. Не нужно использовать List здесь.

public static void main(String[] args) {
    String s = "a dog is running crazily on the ground who doesn't care about the world";
    s = s.replaceAll("[^a-zA-Z]", ""); // replace everything that is not between A-Za-z 
    s = s.toLowerCase();
    s = s.replaceAll("(.)(?=.*\\1)", ""); // replace duplicate characters.
    System.out.println(s);
    System.out.println(s.length()); // 18 : So, Nope

    s = "a dog is running crazily on the ground who doesn't care about the world qwertyuioplkjhgfdsazxcvbnm";
    s = s.replaceAll("[^a-zA-Z]", "");
    s = s.toLowerCase();        
    s = s.replaceAll("(.)(?=.*\\1)", "");
    System.out.println(s);
    System.out.println(s.length()); //26 (check last part added to String)  So, Yes

}

Ответ 4

O (n) решение

static Set<Integer> alphabet = new HashSet<>(26);

public static void main(String[] args) {

    int cnt = 0;

    String str = "a dog is running crazily on the ground who doesn't care about the world";

    for (char c : str.toCharArray()) {
        int n = c - 'a';
        if (n >= 0 && n < 26) {
            if (alphabet.add(n)) {
                cnt += 1;
                if (cnt == 26) {
                    System.out.println("found all letters");
                    break;
                }
            }
        }
    }
}

Ответ 5

Добавление в ответ @Leon, создание List и удаление из него кажется совершенно ненужным. Вы можете просто выполнить цикл 'a' - 'z' и выполнить проверку с каждым char. Кроме того, вы просматриваете весь String, чтобы узнать, присутствует ли каждая буква. Но лучшей версией было бы перебрать каждую букву. Это может безопасно защитить вас несколькими итерациями.

В итоге простой пример может выглядеть так:

// This is the string- I've just put a random example
String str = "a dog is running crazily on the ground who doesn't care about the world";
str = str.toLowerCase();

boolean success = true;
for(char c = 'a';c <= 'z'; ++c) {
    if(!str.contains(String.valueOf(c))) {
        success = false;
        break;
    }
}

if (success)
    System.out.println("String contains all alphabets");
else
    System.out.println("String DOESN'T contains all alphabets");

Ответ 6

Еще один ответ уже указал причину исключения. Вы неправильно использовали List.remove(), поскольку он неявно преобразовывал char в int, который он назвал List.remove(int), который удаляет по индексу.

Способы решения на самом деле легки. Вы можете заставить его вызвать List.remove(Object) на

alphabets.remove((Character) inp);

Некоторые другие улучшения:

  • В этом случае вы должны использовать Set вместо List.
  • Вы даже можете использовать boolean[26] для отслеживания появления алфавита.
  • Вам не нужно преобразовывать строку в массив char. Просто выполните str.charAt(index), чтобы дать вам символ в определенной позиции.

Ответ 7

Для сохранения этой информации достаточно одной целочисленной переменной. Вы можете сделать это так:

public static boolean check(String input) {
  int result = 0;    
  input = input.toLowerCase();
  for (int i = 0; i < input.length(); i++) {
    char c = input.charAt(i);
    if (c >= 'a' && c <= 'z') {
      result |= 1 << (input.charAt(i) - 'a');
    }
  }
  return result == 0x3ffffff;
}

Каждый бит соответствует букве на английском алфавите. Поэтому, если ваша строка содержит все буквы, результат будет иметь форму 00000011111111111111111111111111

Ответ 8

Как создать

List<String> alphabets = new ArrayList <String> ();

и добавить значения как строки

затем

for (String val : alphabets) {   // if str is long this will be more effecient
     if (str.contains (val) == false) {
        System.out.println ("FAIL");
        break;
     }
}

Ответ 9

Вы можете избавиться от исключения, изменив эту строку в своем коде

char inp = strChar[i];

к

Character inp = strChar[i];

Обратитесь https://docs.oracle.com/javase/7/docs/api/java/util/List.html#remove(java.lang.Object)

List.remove('char') рассматривается как List.remove('int'), поэтому вы получаете indexOutOfBoundsException, потому что он проверяет значение ASCII 'a', которое равно 97. Преобразование переменной 'inp' в Character вызывало бы List.remove('Object') апи.

Ответ 10

И если вам нравятся потоки Java 8, такие как я:

final List<String> alphabets = new ArrayList<>();

И после заполнения алфавитов с помощью a-z:

final String str = "a dog is running crazily on the ground who doesn't care about the world";
final String strAsLowercaseAndWithoutOtherChars = str.toLowerCase()
                                                     .replaceAll("[^a-z]", "");

final boolean anyCharNotFound = alphabets.parallelStream()
       .anyMatch(t -> !strAsLowercaseAndWithoutOtherChars.contains(t));

if (anyCharNotFound) {
    System.out.println("String DOESN'T contains all alphabets");
} else {
    System.out.println("String contains all alphabets");
}

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

Ответ 11

Для Java 8 его можно записать так:

boolean check(final String input) {
    final String lower = input.toLowerCase();
    return IntStream.range('a', 'z'+1).allMatch(a -> lower.indexOf(a) >= 0);
}

Ответ 12

Просто сделайте что-нибудь вроде

sentence.split().uniq().sort() == range('a', 'z')

Ответ 13

Здесь другое наивное решение, которое использует String.split("") для разбиения каждого символа на массив String[], затем Arrays.asList(), чтобы преобразовать его в List<String>. Затем вы можете просто вызвать yourStringAsList.containsAll(alphabet), чтобы определить, содержит ли ваш String алфавит:

String yourString = "the quick brown fox jumps over the lazy dog";

List<String> alphabet = Arrays.asList("abcdefghijklmnopqrstuvwxyz".split(""));
List<String> yourStringAsList = Arrays.asList(yourString.split(""));

boolean containsAllLetters = yourStringAsList.containsAll(alphabet);

System.out.println(containsAllLetters);

Этот подход может быть не самым быстрым, но я считаю, что код легче понять, чем решения, предлагающие циклы и потоки и многое другое.

Ответ 14

Character inp = strChar[i]; 

Используйте это вместо char, метод удаления списка имеет 2 перегруженных метода, один с объектом и один с int. Если вы проходите char, его обрабатывают как int.

Ответ 15

Преобразуйте строку в нижний регистр или в капители. Затем выполните петлю через эквивалентные десятичные значения ascii для A-Z или a-z и верните false, если они не найдены в массиве символов. Вам нужно будет ввести int в char.

Ответ 16

Я думал об игре с кодами символов ASCII.

String toCheck = yourString.toLowerCase();
int[] arr = new int[26];
for(int i = 0; i < toCheck.length(); i++) {
    int c = ((int) toCheck.charAt(i)) - 97;
    if(c >= 0 && c < 26) 
        arr[c] = arr[c] + 1;
}

После запуска цикла вы получаете массив счетчиков, каждый из которых представляет букву алфавита (индекс) и это вхождение в строку.

boolean containsAlph = true;
for(int i = 0; i < 26; i++)
    if(arr[i] == 0) {
        containsAlph = false;
        break;
    }