Dla każdego znaku w ciągu

229

Jak zrobiłbym pętlę for dla każdego znaku w łańcuchu w C ++?

Jack Wilsdon
źródło
9
Jaki rodzaj sznurka? Ciąg C lub std::string?
Tajemniczy
Jest odczytywany z pliku tekstowego, więc
zakładam,
4
Jakiego rodzaju postać? char, Punkt kodowy Unicode, rozszerzony klaster grafemowy?
Philipp
Możliwy duplikat Jak mogę iterować przez ciąg, a także znać indeks (bieżąca pozycja)? . Nie martw się o indexczęść w odpowiedziach.
jww

Odpowiedzi:

417
  1. Pętlowanie znaków a std::string, przy użyciu pętli opartej na zakresie (pochodzi z C ++ 11, obsługiwanej już w najnowszych wersjach GCC, clang i VC11 beta):

    std::string str = ???;
    for(char& c : str) {
        do_things_with(c);
    }
    
  2. Pętla po znakach std::stringiteratorów:

    std::string str = ???;
    for(std::string::iterator it = str.begin(); it != str.end(); ++it) {
        do_things_with(*it);
    }
    
  3. Pętlowanie przez postacie std::stringze staroświecką pętlą for:

    std::string str = ???;
    for(std::string::size_type i = 0; i < str.size(); ++i) {
        do_things_with(str[i]);
    }
    
  4. Pętla przez znaki tablicy znaków zakończonej znakiem null:

    char* str = ???;
    for(char* it = str; *it; ++it) {
        do_things_with(*it);
    }
    
R. Martinho Fernandes
źródło
4
@Robinson: To błędne założenie. Bardzo błędne założenie. Ponadto „charakter” ma tak wiele różnych znaczeń, że najlepiej jest unikać tego terminu.
Szczeniak
6
@Robinson: „std :: string to UTF8 (zakłada się, że jest) ” Od kiedy ?!
Wyścigi lekkości na orbicie
2
No cóż, OK, nie ma kodowania, jednak biorąc pod uwagę wszechobecność utf8 teraz (szczególnie w Internecie) i fakt, że można chcieć jednego spójnego kodowania w potoku lub aplikacji, na podstawie tej dyskusji moje std :: strings są wszystkie utf8: p.
Robinson
4
@Robinson: I wszystkie moje są traktowane jako bez kodowania, ponieważ nie programuję w domenie, w której znajdują się użytkownicy (tzn. Nie ma ciągów przeznaczonych do renderowania dla ludzi). Jeśli chcesz porozmawiać o kodowania znaków, trzeba mówić o wyższym poziomie abstrakcji na górze std::string , która jest po prostu seria bajtów.
Wyścigi lekkości na orbicie
1
również przypadki 2 i 3 są dobrym przykładem tego, gdzie można / należy użyć „auto”
galois
29

Pętlę for można zaimplementować w następujący sposób:

string str("HELLO");
for (int i = 0; i < str.size(); i++){
    cout << str[i];
}

Spowoduje to wydrukowanie łańcucha znak po znaku. str[i]zwraca znak przy indeksie i.

Jeśli jest to tablica znaków:

char str[6] = "hello";
for (int i = 0; str[i] != '\0'; i++){
    cout << str[i];
}

Zasadniczo powyżej dwóch są dwa typy ciągów obsługiwanych przez c ++. Drugi nazywa się ciągiem c, a pierwszy ciągiem std lub (ciągiem c ++). Sugerowałbym użycie ciągu c ++, co jest łatwe w obsłudze.


źródło
24

We współczesnym C ++:

std::string s("Hello world");

for (char & c : s)
{
    std::cout << "One character: " << c << "\n";
    c = '*';
}

W C ++ 98/03:

for (std::string::iterator it = s.begin(), end = s.end(); it != end; ++it)
{
    std::cout << "One character: " << *it << "\n";
    *it = '*';
}

W przypadku iteracji tylko do odczytu można użyć std::string::const_iteratorw C ++ 98 for (char const & c : s)lub tylko for (char c : s)w C ++ 11.

Kerrek SB
źródło
Oto kilka opcji dla kompilatorów z częściową obsługą C ++ 11: pastebin.com/LBULsn76
Benjamin Lindley
@BenjaminLindley: Dzięki! autojest zawsze dobrym pomysłem. Podczas korzystania z niego rozróżnienie między begin()i cbegin()staje się istotne.
Kerrek SB
2
Jaka jest rola odwołania w char tutaj ( char & c)? Czy to po prostu pozwala na modyfikację wartości postaci w przypadku, gdy jest to potrzebne?
LunaticSoul,
11

Oto inny sposób na zrobienie tego przy użyciu standardowego algorytmu.

#include <iostream>
#include <string>
#include <algorithm>

int main()
{
   std::string name = "some string";
   std::for_each(name.begin(), name.end(), [] (char c) {
      std::cout << c;
   });
}
0xBADF00
źródło
Mamy rok 2018, więc to powinna być poprawna odpowiedź.
rwst
7
const char* str = "abcde";
int len = strlen(str);
for (int i = 0; i < len; i++)
{
    char chr = str[i];
    //do something....
}
demoncodemonkey
źródło
4
(Nieaktualny komentarz, który prawdopodobnie jest nadal istotny dla OP :) Nie uważa się za dobrą formę do użycia strlenw warunku pętli, ponieważ wymaga ona operacji O (n) na łańcuchu dla każdej iteracji, co powoduje, że cała pętla O (n ^ 2) w rozmiarze ciągu. strlenw pętli można wywołać warunek, jeśli łańcuch zmienia się podczas pętli, ale powinien być zarezerwowany dla przypadków, w których jest to faktycznie wymagane .
Magnus Hoff
@MagnusHoff: Tak, malarz Schlemiel znów podnosi brzydką głowę.
Fred Larson
Zredagowałem swoją odpowiedź. Magnus masz rację, oops
używałem
Powinieneś jednak nadal używać strlen () poza pętlą zamiast testowania na wartość null w każdej iteracji.
mckenzm
4

Nie widzę żadnych przykładów używania zakresu opartego na pętli z „ciągiem c”.

char cs[] = "This is a c string\u0031 \x32 3";

// range based for loop does not print '\n'
for (char& c : cs) {
    printf("%c", c);
}

nie spokrewnione, ale int przykład tablicy

int ia[] = {1,2,3,4,5,6};

for (int& i : ia) {
    printf("%d", i);
}
10SecTom
źródło
1

W przypadku C-string ( char []) powinieneś zrobić coś takiego:

char mystring[] = "My String";
int size = strlen(mystring);
int i;
for(i = 0; i < size; i++) {
    char c = mystring[i];
}

Dla std::stringmożna użyć str.size(), aby uzyskać jego rozmiar i powtórzyć, jak na przykład, czy można użyć iterator:

std::string mystring = "My String";
std::string::iterator it;
for(it = mystring.begin(); it != mystring.end(); it++) {
    char c = *it;
}
Tiago Pasqualini
źródło
1
for (int x = 0; x < yourString.size();x++){
        if (yourString[x] == 'a'){
            //Do Something
        }
        if (yourString[x] == 'b'){
            //Do Something
        }
        if (yourString[x] == 'c'){
            //Do Something
        }
        //...........
    }

Łańcuch jest w zasadzie tablicą znaków, dlatego możesz określić indeks, aby uzyskać znak. Jeśli nie znasz indeksu, możesz go przeglądać jak w powyższym kodzie, ale robiąc porównanie, upewnij się, że używasz pojedynczych cudzysłowów (które określają znak).

Poza tym powyższy kod jest oczywisty.

prawie początkujący
źródło
-1

możesz pobrać każdy znak w ciągu używając funkcji at biblioteki ciągów, tak jak ja to zrobiłem

string words;
    for (unsigned int i = 0; i < words.length(); i++)
        {
            if (words.at(i) == ' ')
            {
                spacecounter++;    // to count all the spaces in a string
                if (words.at(i + 1) == ' ')
                {
                    i += 1;
                }

to tylko fragment mojego kodu, ale chodzi o to, że możesz uzyskać dostęp do znaków przez stringname.at(index)

Shuja Ul Hasan
źródło