J'essaie de vérifier si une chaîne contient toutes les lettres de l'alphabet. J'ai créé une ArrayList
qui contient tout l'alphabet. J'ai converti la chaîne en tableau de caractères et je parcours le tableau de caractères. Pour chaque caractère présent dans la variable ArrayList
, j'en retire un élément. Et à la fin, j'essaie de vérifier si la Arraylist
est vide pour voir si tous les éléments ont été supprimés. Cela indiquerait que la chaîne contient toutes les lettres de l'alphabet.
Malheureusement, le code renvoie une erreur IndexOutOfBoundsException
à l'intérieur de la condition if, où je supprime des éléments de l'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");
Toutes ces solutions semblent faire beaucoup de travail pour une vérification relativement simple, en particulier compte tenu de l'API de flux de Java 8:
/* Your lowercase string */.chars()
.filter(i -> i >= 'a' && i <= 'z').distinct().count() == 26;
Edit: pour la vitesse
Si vous souhaitez mettre fin à l'itération de chaîne dès que l'alphabet entier est trouvé, vous pouvez suivre en interne 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
De cette façon, le flux cessera dès que la Set
sera remplie avec les 26 caractères requis.
Vous trouverez ci-dessous certaines solutions (encore plus efficaces) en termes de performances, mais en guise de remarque personnelle, je vous dirai de ne pas vous perdre dans l'optimisation prématurée, où vous pourriez avoir une lisibilité et moins d'effort pour écrire le code lui-même.
List.remove
supprime par index. Puisqu'un char
peut être converti en un entier, vous supprimez effectivement les valeurs d'index inexistantes, c'est-à-dire que le caractère 'a' est égal à int 97. Comme vous pouvez le voir, votre liste ne contient pas 97 entrées.
Vous pouvez faire alphabet.remove(alphabets.indexOf(inp))
;
Comme l'ont souligné @Scary Wombat ( https://stackoverflow.com/a/39263836/1226744 ) et @Kevin Esche ( https://stackoverflow.com/a/39263917/1226744 ), il existe une meilleure alternative à votre algorithme
Regex est votre ami . Pas besoin d'utiliser une List
ici.
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
}
O (n) solution
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;
}
}
}
}
}
Ajouter à @Leon answer, créer une List
et le supprimer semble tout à fait inutile. Vous pouvez simplement boucler sur 'a' - 'z'
et faire une vérification avec chaque char
. De plus, vous parcourez toute la String
pour savoir si chaque lettre est présente. Mais la meilleure version serait de boucler chaque lettre elle-même. Cela peut éventuellement vous protéger en quelques itérations.
À la fin, un exemple simple pourrait ressembler à ceci:
// 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");
Une autre réponse a déjà indiqué le motif de l'exception. Vous avez mal utilisé List.remove()
, car il convertit implicitement char
en int
qu’il a appelé List.remove(int)
et qui le supprime par index.
La façon de résoudre est en réalité facile. Vous pouvez le faire appeler le List.remove(Object)
par
alphabets.remove((Character) inp);
Quelques autres améliorations:
Set
au lieu de List
dans ce cas.boolean[26]
pour savoir si un alphabet est apparustr.charAt(index)
pour vous donner le personnage à une certaine position.Une variable entière suffit pour stocker cette information. Tu peux le faire comme ça
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;
}
Chaque bit correspond à une lettre en alphabet anglais. Donc, si votre chaîne contient toutes les lettres, le résultat sera de la forme 00000011111111111111111111111111
Que diriez-vous de créer
List<String> alphabets = new ArrayList <String> ();
et ajouter des valeurs en tant que chaînes
puis
for (String val : alphabets) { // if str is long this will be more effecient
if (str.contains (val) == false) {
System.out.println ("FAIL");
break;
}
}
Vous pouvez vous débarrasser de l'exception en changeant cette ligne dans votre code
char inp = strChar[i];
à
Character inp = strChar[i];
Référez-vous https://docs.Oracle.com/javase/7/docs/api/Java/util/List.html#remove(Java.lang.Object)
List.remove('char')
est traité comme List.remove('int')
, raison pour laquelle vous obtenez indexOutOfBoundsException, car il vérifie la valeur ASCII
de 'a' qui correspond à 97. La conversion de la variable 'inp' en caractère appelle List.remove('Object')
api.
Et si vous aimez les flux Java 8 comme moi:
final List<String> alphabets = new ArrayList<>();
Et après avoir rempli les alphabets avec 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");
}
Ceci convertit la chaîne en minuscules (ignore si vous ne recherchez que les lettres minuscules), supprime tous les caractères de la chaîne qui ne sont pas des lettres minuscules, puis recherche tous les membres de votre alphabets
s'ils sont contenus dans la chaîne à l'aide un flux parallèle.
Pour Java 8, cela pourrait être écrit comme suit:
boolean check(final String input) {
final String lower = input.toLowerCase();
return IntStream.range('a', 'z'+1).allMatch(a -> lower.indexOf(a) >= 0);
}
Voici une autre solution naïve qui utilise String.split("")
pour scinder chaque caractère dans un tableau String[]
, puis Arrays.asList()
pour le convertir en List<String>
. Vous pouvez alors simplement appeler yourStringAsList.containsAll(alphabet)
pour déterminer si votre String
contient l'alphabet:
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);
Cette approche n'est peut-être pas la plus rapide, mais je pense que le code est un peu plus facile à comprendre que les solutions proposant des boucles et des flux, etc.
Juste faire quelque chose comme
sentence.split().uniq().sort() == range('a', 'z')
Character inp = strChar[i];
Utilisez ceci au lieu de char
, la méthode de suppression de liste a 2 méthodes surchargées, une avec objet et une avec int. Si vous transmettez un caractère, il est traité comme un entier.
Convertissez la chaîne en minuscule ou en majuscule. Ensuite, parcourez les valeurs décimales ascii équivalentes pour A-Z ou a-z et renvoyez false si elles ne figurent pas dans le tableau de caractères. Vous devrez lancer l'int à char.
J'ai pensé jouer avec les codes ASCII des personnages.
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;
}
Après avoir exécuté la boucle, vous obtenez éventuellement un tableau de compteurs, chacun représentant une lettre d'alphabet (index) et son occurrence dans la chaîne.
boolean containsAlph = true;
for(int i = 0; i < 26; i++)
if(arr[i] == 0) {
containsAlph = false;
break;
}