Durch einen leeren String iterieren, oder mit do while leeren String erstmalig befüllen und gleichzeitig durchgehen.



  • Ich will die die Zeichen in einem String zählen.
    Jedoch will ich die schon gezählten Buchstaben auslassen, damit keine "Buchstaben:Zahl" doppelt ausgegeben wird.
    Ich habe primär das Problem das ich immer mit einem leeren array oder string vergleichen will bzw durch iterieren will.
    Bei dem Ansatz mit einer do while hatte ich das gelöst, aber ich bekam immer ein std::out_of_range expetion.
    Daher der versuch mit iterator, da ja genau das vor solchen Kopfschmerzen bewahren soll, doch durch einen leeren String will er nicht iterieren daher der versuch mit string done = " "; dann kommt wenigstens etwas, aber mit eine komischen Ausgabe und einem zusätzlichen error.

    Bin für jede Hilfe dankbar!

    /*### MIT ITERATOR #####*/
    #include <iostream>
    #include <string>
    #include <vector>
    using namespace std;
    
    int letterCounter(string text, char c) { // Zählt Char in einem String und gibt die Zahl zurück
        int counted = 0;
        for (int i = 0; i < text.length(); i++) {
            if (text.at(i) == c) {
                counted++;
            }
        }
        return counted;
    }
    
    int main()
    {
        while(true){
            string text = "";
            string done = " ";
            cout << "Please enter a text: ";
            cin >> text;
    
            string::iterator it;
    
            for (int i = text.length()-1; i >= 0; i--) { // for schleife die den String durchläuft
                for (it = done.begin(); it != done.end(); ++it) { // iterator durch die done list - Problem: Die Done-"Liste" ist anfangs leer.
                    if (text[i] == *it) {
                       // do nothing
                    }
                    else {
                        done.append(to_string(text.at(i)));
                        cout << text.at(i) << "(" << letterCounter(text, text.at(i)) << ")";
                    }
                }
            }
            cout << "\n";
        }
    }
    
    */### OHNE ITERATOR ######*/
    
    for (int i = text.length()-1; i >= 0; i--) { // for schleife die den String durchläuft
         int j = done.size();
                do {
                    if (text.at(i) == done.at(j)) {
                        // do nothing
                    }
                    else {
                        
                        done.append(to_string(text.at(i)));
                        cout << letterCounter(text, text.at(i));
                        j--;
                    }
                } while (j >= 0);
    }
    


  • Ist das nur eine Übungsaufgabe, denn sonst würde sich dafür eine std::map<char, size_t> anbieten?

    Und bei deinem Code ist der else-Code an der falschen Stelle. Erstelle dir am besten dafür eine eigene Funktion, welche die Anzahl der bisher gleichen Zeichen ermittelt und frage diese dann innerhalb der (ersten bzw. dann dort einzigen) Schleife ab.



  • Was hat das Problem mit Iterator oder Index zu tun? Deine Lösung ist for statt do/while.



  • Ist das nur eine Übungsaufgabe, denn sonst würde sich dafür eine std::map<char, size_t> anbieten?

    Ich dachte eher an ein set<char>. Oder für stings, die lang sind, ein array mit 256 ints (oder wie groß char ist).



  • Mit einem set kann man aber nicht zählen (es soll wohl ein Histogramm ausgegeben werden, also wie oft jeder Buchstabe im Text vorkommt, aber nur die Buchstaben ausgeben, welche auch mindestens 1x vorkommen - und die Ausgabe aber nicht mehrmals je Buchstabe).

    Und mit einer map ist das dann ein 2-Zeiler (+ noch die Ausgabe, welche ebenfalls nur 2 Zeilen umfaßt) - und jeweils mittels Range-based for loop sogar so kurz wie möglich.



  • @Th69 Das hab ich vergessen zu erwähnen mit einer map hab ich schon eine Lösung aber ich wollte es expliziet mit einem iterator oder do while lösen. Aber sonst erscheint mir eine map als die schönste Lösung.



  • Warum den Overhead einer std::map in Kauf nehmen? Ein std::array<unsigned int,256> tut´s auch, dann ist das Zeichen der Index im Array.



  • nimm

    bool x=true;           
    for (it = done.begin(); it != done.end(); ++it)  // iterator durch die done list - Problem: Die Done-"Liste" ist anfangs leer.
      if (text[i] == *it) 
        x= false;
    
    if (x) {
      done.append(to_string(text.at(i)));
      cout << text.at(i) << "(" << letterCounter(text, text.at(i)) << ")";
    }
    

    anstelle

                for (it = done.begin(); it != done.end(); ++it) { // iterator durch die done list - Problem: Die Done-"Liste" ist anfangs leer.
                                        if (text[i] == *it) {
                                           // do nothing
                                        }
                                        else {
                                            done.append(to_string(text.at(i)));
                                            cout << text.at(i) << "(" << letterCounter(text, text.at(i)) << ")";
                                        }
                                            
    


  • Da es ein klar umrissenes Problem ist, würde ich es vermutlich so lösen. Die Range-Based-Loops lassen sich natürlich wahlweise durch andere Schleifen-Konstrukte ersetzen.

    #include <iostream>
    #include <vector>
    #include <string>
    
    int main()
    {
        std::string Text = "F00B4r 1st e1n KuRz3s W0rt";
        // Zeichen als Index im Vector
        std::vector<uint32_t> SignCounter( 256, 0 );
        // Laufen ueber den Text und erhoehen fuer jedes Zeichen die Anzahl
        for ( auto &sign : Text )
            ++SignCounter[ (unsigned char)sign ];
        for ( unsigned i = 0; i < SignCounter.size(); ++i )
        {
            if ( SignCounter[ i ] > 0 )
                std::cout << "Zeichen '" << (char)i  << "': " << SignCounter[ i ] << "\n";
        }
        return 0;
    }
    

Log in to reply