J'ai besoin d'un Iterator<Character>
à partir d'un objet String
. Existe-t-il une fonction disponible dans Java qui me fournit cela ou dois-je coder la mienne?
Une option consiste à utiliser Goyave :
ImmutableList<Character> chars = Lists.charactersOf(someString);
UnmodifiableListIterator<Character> iter = chars.listIterator();
Cela produit une liste immuable de caractères qui est sauvegardée par la chaîne donnée (aucune copie nécessaire).
Toutefois, si vous finissez par le faire vous-même, je vous recommanderais de ne pas exposer la classe d'implémentation pour la variable Iterator
, comme le font un certain nombre d'autres exemples. Je recommanderais plutôt de créer votre propre classe d'utilitaires et d'exposer une méthode d'usine statique:
public static Iterator<Character> stringIterator(final String string) {
// Ensure the error is found as soon as possible.
if (string == null)
throw new NullPointerException();
return new Iterator<Character>() {
private int index = 0;
public boolean hasNext() {
return index < string.length();
}
public Character next() {
/*
* Throw NoSuchElementException as defined by the Iterator contract,
* not IndexOutOfBoundsException.
*/
if (!hasNext())
throw new NoSuchElementException();
return string.charAt(index++);
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
Cela n'existe pas, mais c'est simple à implémenter:
class CharacterIterator implements Iterator<Character> {
private final String str;
private int pos = 0;
public CharacterIterator(String str) {
this.str = str;
}
public boolean hasNext() {
return pos < str.length();
}
public Character next() {
return str.charAt(pos++);
}
public void remove() {
throw new UnsupportedOperationException();
}
}
La mise en œuvre est probablement aussi efficace que possible.
for (char c : myString.toCharArray()) {
}
Voler quelqu'un d'autre dans une autre réponse, c'est probablement la meilleure implémentation directe (si vous n'utilisez pas de goyave).
/**
* @param string
* @return list of characters in the string
*/
public static List<Character> characters(final String string) {
return new AbstractList<Character>() {
@Override
public Character get(int index) {
return string.charAt(index);
}
@Override
public int size() {
return string.length();
}
};
}
Réponse courte: Non, vous devez le coder.
Réponse longue: List et Set ont tous deux une méthode pour obtenir un Iterator (il existe quelques autres classes de collection, mais probablement pas ce que vous recherchez). Les interfaces List et Set font partie de Collections Framework qui permet uniquement d’ajouter/de supprimer/itérer des objets tels que Character ou Integer (et non des primitives telles que char ou int). Il existe une fonctionnalité dans Java 1.5 appelée auto-boxing qui cachera cette conversion de primitive en objet, mais je ne la recommande pas et elle ne fournira pas ce que vous voulez dans ce cas.
Une alternative serait d’envelopper la chaîne dans une classe de votre choix qui
implements Iterator<Character>
mais cela pourrait être plus de travail que cela ne vaut.
Voici un extrait de code pour faire ce que vous voulez:
String s = "";
List<Character> list = new ArrayList<Character>(s.length());
for (int i = 0; i < s.length(); i++) {
// note that Character.valueOf() is preferred to new Character()
// you can omit the Character.valueOf() method
// and Java 1.5+ will auto-box the primitive into an Object
list.add(Character.valueOf(s.charAt(i)));
}
Iterator<Character> iterator = list.iterator();
CharacterIterator it = new StringCharacterIterator("abcd");
// Iterate over the characters in the forward direction
for (char ch=it.first(); ch != CharacterIterator.DONE; ch=it.next())
// Iterate over the characters in the backward direction
for (char ch=it.last(); ch != CharacterIterator.DONE; ch=it.previous())
Cela peut être fait avec un peu d'aide de Apache Commons Lang (si vous ne voulez pas utiliser Guava et que vous voulez un vrai Java.util.Iterator
.
private static Iterator<Character> iterator(String string) {
return Arrays.asList(ArrayUtils.toObject(string.toCharArray())).iterator();
}
Pas de moyen direct. Pas difficile à coder, cependant:
public static Iterator<Character> gimmeIterator(final String x) {
Iterator<Character> it = new Iterator<Character>() {
String str = x == null ? "" : x;
int pos = -1; // last read
public boolean hasNext() { return(pos+1 < str.length()); }
public Character next() { pos++; return str.charAt(pos); }
public void remove() {
throw new UnsupportedOperationException("remove unsupported for this iterator");
}
};
return it;
}
Cela semble sale, mais vous pouvez utiliser Scanner avec un séparateur de chaîne vide:
Scanner scanner = new Java.util.Scanner(myInput).useDelimiter("");
Le scanner implémente Iterator
, donc scanner
est maintenant une Iterator
de longueur-1 chaînes, qui est proche.
Pour continuer avec le (très?) Sale, dans Java 8, vous pouvez le faire pour itérer succinctement des caractères:
for (String s: (Iterable<String>)() -> scanner) {
char c = s.charAt(0);
System.out.println(c);
}
Pour savoir pourquoi () -> scanner
fonctionne (et pourquoi cela peut être dangereux, mais pas dans ce cas d'utilisation), voir Expliquez comment ce lambda peut être affecté à un Iterable .
Avec Java 8 ou plus récent, vous pouvez utiliser la fonction de flux. Avec la méthode chars()
, vous pouvez accéder à une IntStream
. IntStream
prend en charge la méthode iterator()
qui renvoie un itérateur OfInt
. OfInt
implémente Iterator<Integer>
.
String str = "foobar";
OfInt ofit = str.chars().iterator();
Iterator<Integer> it = ofit;
Ce n'est pas une réponse parfaite, puisque vous avez demandé Iterator <Character>.
Btw: Avec str.codePoints (), vous pouvez également accéder à un point de code IntStream.
La Iterator itérer sur une collection ou quoi que ce implémente. La classe String n'effectue pas cette interface. Donc, il n'y a pas de moyen direct.
Pour itérer sur une chaîne, vous devez d'abord créer un tableau de caractères à partir de cette chaîne, puis une collection dans ce tableau de caractères.