String zerlegen und teilweise wieder zusammensetzen



  • Die Zeile ist mir irgendwie nicht ganz klar ...

    //...
    ptr = strtok(NULL, "\\");
    //...
    

    Vielleicht würden dem Quelltext auch ein paar Kommentare guttun. 😉


  • Mod

    Mitleid schrieb:

    Die Zeile ist mir irgendwie nicht ganz klar ...

    //...
    ptr = strtok(NULL, "\\");
    //...
    

    Vielleicht würden dem Quelltext auch ein paar Kommentare guttun. 😉

    Das ist tatsächlich, wie man strtok benutzt, habe ich schon nachgeschlagen. Gräßlich, nicht wahr?

    Ich glaube, das mit der falschen Arraygröße war's schon, ich konnte den Fehler nämlich nicht mehr nachvollziehen, nachdem ich das bei mit korrigiert habe. Könnte natürlich gut sein, dass noch mehr undefiniertes Verhalten drin ist und ich Glück hatte. Mal sehen was der threadersteller nach der Korrektur zu sagen hat.



  • Mitleid schrieb:

    Die Zeile ist mir irgendwie nicht ganz klar ...

    //...
    ptr = strtok(NULL, "\\");
    //...
    

    Vielleicht würden dem Quelltext auch ein paar Kommentare guttun. 😉

    Einfach mal nachgucken was strtok ist. Wird 0 übergeben, wird die Suche nach dem nächsten token fortgesetzt.
    Dem Quelltext würde einiges gut tun. Vor allem auch ein delete[]. Oder ein new weniger und wie gesagt den C Kram durch C++ ersetzen.



  • Code:
    #include<cstring>
    #include <vcl.h>
    #pragma hdrstop

    # include <iostream>

    #include <stdio>
    #include <stdlib>
    //---------------------------------------------------------------------------

    #pragma argsused

    using namespace std;

    int main()
    {
    char string[20] = "lala\\bubu\\wert\";

    char *ptr;
    char *Mist = new char[strlen(string)];

    ptr = strtok(string, "\"); //zerlegt string, bei dem zeichen "\"
    // cout << ptr << endl;

    strncat(Mist, ptr, strlen(ptr));
    strncat(Mist, "\", strlen(ptr));

    int i =0;

    while(i < 1)
    {
    ptr = strtok(NULL, "\"); // damit es nach erster zerlegung weiter geht

    strncat(Mist, ptr, strlen(ptr));
    strncat(Mist, "\", strlen(ptr));
    i++;
    cout << Mist << endl;
    }

    getchar();
    return 0;
    }
    [/code]

    danke für die hinweise,
    so habs erstmal etwas verbessert.
    wie kann man mit den funktionen der string klasse anhand eines bestimmten zeichens eine string zerlegen?



  • SeppJ schrieb:

    Das ist tatsächlich, wie man strtok benutzt, habe ich schon nachgeschlagen. Gräßlich, nicht wahr?

    Jup

    SeppJ schrieb:

    Ich glaube, das mit der falschen Arraygröße war's schon

    char *Mist = new char[strlen(string)+10];
    //...
    strncat(Mist, ptr, strlen(ptr));
    

    Dürfte noch problematisch sein, je nachem was unter der Adresse Mist alles im Speicher ist.

    Und das da

    strncat(Mist, "\\", strlen(ptr));
    

    sieht mir auch nicht koscher aus. Na ja, weil strlen(ptr) nicht unbedingt etwas mit "\" zu tun hat.

    Aber gut, bin heute irgendwie zu müde mich da tiefer reinzudenken. Kann sein, dass ich Unsinn rede ... 😃



  • nachdem ich die größe angepasst hatte, war der fehler zunächst weg, aber ich bentze grad einen anderen rechner als vorhin, morgen kann ich wieder den zuvor bentzten rechner verwenden und dort werde ich es dann auch nochmal verbessern, um zu sehen ob das eventuell einfluss hat.

    warum ist strtok gräßlich?

    gruß



  • mimus schrieb:

    wie kann man mit den funktionen der string klasse anhand eines bestimmten zeichens eine string zerlegen?

    http://www.cplusplus.com/reference/string/string/

    Der untere Abschnitt enthält ein paar Funktionen, die dich interessieren könnten. Z.B. find_first_of und substr.

    mimus schrieb:

    warum ist strtok gräßlich?

    Shade of Mine wird mir zwar widersprechen, aber ich finde die Verwendung nicht intuitiv. An der Stelle würde in meinen Augen ein Kommentar Wunder wirken, auch wenn es in der Doku steht, dass der Aufruf mit NULL eine spezielle Bedeutung hat. Denn selbst im Hilfetext des Compilers sieht man es nicht auf den ersten Blick.


  • Mod

    mimus schrieb:

    warum ist strtok gräßlich?

    Nicht nur, dass es Nebeneffekte hat, es ist sogar seine hauptsächliche Funktion, Nebeneffekte zu haben. Außerdem (beziehungsweise dadurch) ist aus dem Ausdruck

    ptr = strtok(NULL, "\\");
    

    überhaupt nicht ersichtlich, was er macht, sofern man nicht das Handbuch daneben liegen hat. Wenn man sich das ohne Handbuch anguckt, denkt man folgendes:
    - strtok, aha, string tokenizer. Diese Funktion zerlegt also Strings
    - "//" ist ein typisches Trennzeichen, der zweite Parameter gibt also wahrscheinlich das trennzeichen an.
    - Die Funktion weist einem char* etwas zu. Das werden dann wohl die Tokens sein. Nein, Moment, ein string kann doch mehrere Tokens enthalten. Warum wird dann nur eines zurückgegeben?
    - Woher soll die Funktion überhaupt wissen, welcher string zerlegt werden soll?
    - Und was soll dieses NULL?
    - 😕
    - Ich brauche eine Referenz zu dieser Funktion

    Und das ist eigentlich nicht der Gedankengang, den man beim Angucken einer Funktion aus der Standardbibliothek einer Sprache haben sollte.

    wie kann man mit den funktionen der string klasse anhand eines bestimmten zeichens eine string zerlegen?

    Mittels der diversen find_XXX und substr Methoden. Welche genau, dass hängt davon ab, was man genau haben will.

    Auf dieser Seite findest du ein Beispiel für einen komplett fertigen, Rundum-sorglos-String-Tokenizer:
    http://oopweb.com/CPP/Documents/CPPHOWTO/Volume/C++Programming-HOWTO-7.html
    Dieser kann dann aber schon so viel, dass er wieder kompliziert aussieht. Für das was du vor hast, kann man das auch einfacher lösen.



  • class tokenizer
    {
    public:
        tokenizer(const std::string & s, char c)
        : s_(s), c_(c), from_(0)
        {}
        std::string operator()()
        {
            size_t to = s_.find(c_, from_);
            std::string s = to != std::string::npos  ?
                s_.substr(from_, to-from_) :
                s_.substr(from_);
            from_ = to+1;
            return s;
        }
    private:
        std::string  s_;
        char c_;
        size_t from_;
    };
    
    int main()
    {
        using namespace std;
    
        tokenizer t("hallo welt !", ' ');
        string hallo(t()),
            welt(t());
    
        return 0;
    }
    

    Das kann man sicherlich auch viel besser machen.
    Man kann aber auch z.B. boost::tokenizer benutzen.



  • danke für die vielen infos, ich werd mich mit der string klasse beschäftigen und den code morgen entsprechend umschreiben.

    Vielen Dank



  • so ich hab mir das mit der string klasse mal angesehen und den quelltext auf meine bedürfnisse angepasst(ja leider hab ich mir das nicht selbst ausgedacht...)
    Ich hoffe, dass das so einem passablen Stil entspricht, falls das nicht so ist bin ich für weitere tips sehr dankbar!

    //---------------------------------------------------------------------------
    #include <string>
    #include <algorithm>
    #include <vector>
    #include <vcl.h>
    #include <dir>
    #pragma hdrstop
    
    #include <iostream>
    
    #include <stdio>
    #include <stdlib>
    //---------------------------------------------------------------------------
    
    #pragma argsused
    
    using namespace std;
    int Zerlegen(int i, const string& str, vector<string>& tokens,
                        const string& Trennzeichen = "\\");
    
    int main()
    {
        string Pfad = "C:\\BoneRemo1\\Ordner\\UOrdner";
        vector<string>::iterator ptr;
        vector<string> tokens;
        vector<string> ziel;
        string ausgabe;   // zum Zusammensetzen
        int Size = 0;     // für die Größe des Zielstrings
    
        cout << Pfad << endl;
    
        Size = Zerlegen(Size, Pfad, tokens);
    
        ziel.resize(Size);
    
        copy(tokens.begin(), tokens.end(), ziel.begin());
    
        for (ptr = ziel.begin(); ptr != ziel.end(); ptr++)
        {
    
          ausgabe = ausgabe + *ptr + "\\";
    
          _mkdir(ausgabe.c_str());
    
          cout << ausgabe << endl;
    
        }
        cout << Size << endl;
        getchar();
    }
    
    int Zerlegen(int i, const string& str, vector<string>& tokens,
                        const string& Trennzeichen)
    {
    
        string::size_type lastPos = 0;
        string::size_type pos     = str.find_first_of(Trennzeichen);
    
        while (string::npos != pos || string::npos != lastPos)
        {
            // gefundenen Teilstring in Vector schieben
            tokens.push_back(str.substr(lastPos, pos - lastPos));
            // Trennzeichen überspringen
            lastPos = str.find_first_not_of(Trennzeichen, pos);
            // nächstes Zeichen finden
            pos = str.find_first_of(Trennzeichen, lastPos);
            i++;
        }
        return i;
    }
    

    liebe Grüße und nochmals vielen Dank!!


Anmelden zum Antworten