Comment appliquer la boucle for-each à chaque caractère d'une chaîne?

189

Je veux donc itérer pour chaque caractère d'une chaîne.

Donc je pensais:

for (char c : "xyz")

mais j'obtiens une erreur de compilation:

MyClass.java:20: foreach not applicable to expression type

Comment puis-je faire ceci?

Lyndon White
la source

Réponses:

333

La façon la plus simple de for-each charin a Stringest d'utiliser toCharArray():

for (char ch: "xyz".toCharArray()) {
}

Cela vous donne la concision de for-each construct, mais malheureusement String(ce qui est immuable) doit effectuer une copie défensive pour générer le char[](qui est mutable), donc il y a une pénalité de coût.

De la documentation :

[ toCharArray()renvoie] un tableau de caractères nouvellement alloué dont la longueur est la longueur de cette chaîne et dont le contenu est initialisé pour contenir la séquence de caractères représentée par cette chaîne.

Il existe des façons plus verbeuses d'itérer des caractères dans un tableau (boucle for régulière CharacterIterator, etc.), mais si vous êtes prêt à payer le coût, toCharArray()chacune est la plus concise.

lubrifiants polygènes
la source
1
Le compilateur reconnaîtra-t-il qu'une copie conforme n'est pas nécessaire et appliquera-t-il les optimisations appropriées?
Pacerier
1
@Pacerier Non, les compilateurs Java actuels n'optimiseront jamais le code.
RAnders00
1
@ RAnders00 Donc, dans ce cas, toCharArray( )est appelé 3 fois?
denvercoder9
1
Avec une longueur de chaîne de 211900000, le temps nécessaire pour terminer for (char c : str.toCharArray()) { }est d'environ 250 ms et le temps nécessaire pour terminer for (char c : charArray) { }est <10 ms. Bien sûr, ces valeurs de temps dépendront du matériel, mais le point à retenir est qu'une méthode est beaucoup plus coûteuse que l'autre.
denvercoder9
7
@RafiduzzamanSonnet: Non, le toCharArray()n'est pas à l'intérieur du corps de la boucle; il n'est appelé qu'une seule fois, puis la boucle itère sur ce tableau résultant. (La boucle for-each est différente de la forboucle générale , qui évalue la condition d'arrêt à chaque itération.)
not-just-yeti
50
String s = "xyz";
for(int i = 0; i < s.length(); i++)
{
   char c = s.charAt(i);
}

 

Matthew Flaschen
la source
7
OP attend une boucle for inhanced.
AmitG
3
Down voté parce que ce n'est pas précisément ce que OP a demandé. Bien que ce soit une solution valable, ce n'est pas du tout ce qui est demandé
Sirens
1
Peu importe ce que l'OP attendait, cela a de meilleures performances que pour chacun, je suppose.
Eric Wang
9

Une autre solution utile, vous pouvez travailler avec cette chaîne en tant que tableau de String

for (String s : "xyz".split("")) {
    System.out.println(s);
}
kyxap
la source
Élégant, mais malheureusement, cela ne fonctionne pas si des éléments de la chaîne sont split()mappés à plus d'un caractère Java, ce qui est le cas pour presque toutes les émoticônes. Par exemple, cette variante de votre exemple fera une boucle quatre fois au lieu de trois:for (String s : "x😁z".split("")) { System.out.println(s); }
skomisa
5

Vous devez convertir l'objet String en un tableau de char à l'aide de la toCharArrayméthode () de la classe String:

String str = "xyz";
char arr[] = str.toCharArray(); // convert the String object to array of char

// iterate over the array using the for-each loop.       
for(char c: arr){
    System.out.println(c);
}
codaddict
la source
4

Dans Java 8, nous pouvons le résoudre comme suit:

String str = "xyz";
str.chars().forEachOrdered(i -> System.out.print((char)i));    

La méthode chars () renvoie un IntStreamcomme mentionné dans le doc :

Renvoie un flux de int étendant à zéro les valeurs char de cette séquence. Tout caractère qui correspond à un point de code de substitution est transmis sans être interprété. Si la séquence est mutée pendant la lecture du flux, le résultat n'est pas défini.

Pourquoi utiliser forEachOrderedet nonforEach ?

Le comportement de forEachest explicitement non déterministe où comme forEachOrderedexécute une action pour chaque élément de ce flux, dans l' ordre de rencontre du flux si le flux a un ordre de rencontre défini. Donc, forEachne garantit pas que la commande sera conservée. Vérifiez également cette question pour en plus.

Nous pourrions également utiliser codePoints()pour imprimer, voir cette réponse pour plus de détails.

akhil_mittal
la source
Cela crée plusieurs objets, donc cette réponse n'est pas complète sans la mise en garde que cela peut être moins efficace qu'une simple boucle indexée.
toolforger
4

Malheureusement, Java ne fait pas de Stringmise en œuvre Iterable<Character>. Cela pourrait facilement être fait. Il y a StringCharacterIteratormais cela ne met même pas en œuvre Iterator... Alors faites le vôtre:

public class CharSequenceCharacterIterable implements Iterable<Character> {
    private CharSequence cs;

    public CharSequenceCharacterIterable(CharSequence cs) {
        this.cs = cs;
    }

    @Override
    public Iterator<Character> iterator() {
        return new Iterator<Character>() {
            private int index = 0;

            @Override
            public boolean hasNext() {
                return index < cs.length();
            }

            @Override
            public Character next() {
                return cs.charAt(index++);
            }
        };
    }
}

Maintenant, vous pouvez (un peu) facilement exécuter for (char c : new CharSequenceCharacterIterable("xyz"))...

Ossifer
la source
3

Si vous utilisez Java 8, vous pouvez utiliser chars()sur a Stringpour obtenir un Streamde caractères, mais vous devrez convertir le intdos en a charcomme renvoyant chars()un IntStream.

"xyz".chars().forEach(i -> System.out.print((char)i));

Si vous utilisez Java 8 avec des collections Eclipse , vous pouvez utiliser la méthode de CharAdapterclasse forEachavec une référence lambda ou une méthode pour parcourir tous les caractères d'un fichier String.

Strings.asChars("xyz").forEach(c -> System.out.print(c));

Cet exemple particulier pourrait également utiliser une référence de méthode.

Strings.asChars("xyz").forEach(System.out::print)

Remarque: je suis un committer pour les collections Eclipse.

Donald Raab
la source
1

Vous pouvez également utiliser un lambda dans ce cas.

    String s = "xyz";
    IntStream.range(0, s.length()).forEach(i -> {
        char c = s.charAt(i);
    });
ander4y748
la source
-7

Pour Travers une chaîne, vous pouvez également utiliser charAt() avec la chaîne.

comme :

String str = "xyz"; // given String
char st = str.charAt(0); // for example we take 0 index element 
System.out.println(st); // print the char at 0 index 

charAt() est une méthode de gestion des chaînes en java qui aide à parcourir la chaîne pour un caractère spécifique.

user1690439
la source
2
savez-vous ce que for (char st: "xyz".toCharArray()) {}c'est?
AmitG
Cela ne compilera pas.
Maroun
-1 hors sujet (topic: for-each), et utilisez charAt au lieu de charAT
peenut