Eigenes explode()



  • Moin!
    Es gab immer in PHP so eine schicke Funktion Namens explode(), die einen Array aus Strings zurücklieferte. Anzugeben ist dabei ein String mit der Quelle und ein String mit dem Seperatorzeichen. Also

    $str = "eins|zwei|drei";
    $arr = explode("|", $str) //liefert array("eins", "zwei", "drei") zurück
    

    So etwas ähnliches wollte ich mir in C++ nachbasteln. Mein Code sieht derzeit so aus:

    void explode(vector<string>* vec, string s, string sep)
    {
    	string tmp = s;
    	int pos;
    
    	while((pos = tmp.find(sep)) != string::npos)
    	{
    		vec->push_back(tmp.substr(0, pos));
    		tmp = tmp.substr(pos);
    	}
    }
    

    Die while-Schleife terminiert nicht. Es wird lediglich das erste Element gelesen und dann bleibt tmp immer gleich. Irgendwie habe ich mich festgefahren und mein debugger spinnt ein wenig (Man sollte keinen Beta-Quatsch zum entwickeln einsetzen 🙄 )



  • Wenn

    pos = tmp.find(sep);
    

    einmal etwas gefunden hat dann findet es immer wieder die selbe stelle.
    Lösung:

    tmp = tmp.substr(pos + sep.length() );
    

    Kurt



  • Danke. Genau das war's!



  • Noch ein Lösungsvorschlag:

    void explode( vector<string>& res, string const& str, string const& sep )
    {
      string::size_type begin = 0, end;
      while ((end = str.find(sep, begin)) != string::npos) {
        res.push_back(str.substr(begin, end-begin));
        begin = end + sep.length();
      }
      res.push_back(str.substr(begin));
    }
    


  • Kann man die Funktion auch so programmieren das man den push_back Aufruf nur an einer Stelle im Code hat? Also das man kein seperates push_back für das letzte Token braucht...



  • Ich bin für das hier -->

    void stringExplode(vector<string>& vec, string const& line, string const& delims)
    {
        string::size_type begIdx, endIdx = 0;
        while( (begIdx = line.find_first_not_of(delims, endIdx))!= string::npos )
        {
            endIdx = line.find_first_of(delims, begIdx);
            vec.push_back( line.substr(begIdx, endIdx - begIdx) );
        }
    }
    

    hmpf fehler korrigiert^^



  • :)- schrieb:

    Kann man die Funktion auch so programmieren das man den push_back Aufruf nur an einer Stelle im Code hat? Also das man kein seperates push_back für das letzte Token braucht...

    void explode( vector<string>& res, string const& str, string const& sep )
    {
      string::size_type begin = 0, end;
      do {
        end = str.find(sep, begin);
        res.push_back(str.substr(begin, end-begin));
        begin = end + sep.length();
      } while (end != string::npos);
    }
    

    Ging ja nur fix um's Prinzip.. da gibt's sicher noch einiges zu verbessern.



  • aber deine variante hat jetzt 2 x nen find Aufruf und ist somit wahrscheinlich lahmer 🤡 😞



  • Morgen,

    nicht zu vergessen: boost::algorithm::split 😉

    mfg
    v R



  • finix schrieb:

    :)- schrieb:

    Kann man die Funktion auch so programmieren das man den push_back Aufruf nur an einer Stelle im Code hat? Also das man kein seperates push_back für das letzte Token braucht...

    void explode( vector<string>& res, string const& str, string const& sep )
    {
      string::size_type begin = 0, end;
      do {
        end = str.find(sep, begin);
        res.push_back(str.substr(begin, end-begin));
        begin = end + sep.length();
      } while (end != string::npos);
    }
    

    Ging ja nur fix um's Prinzip.. da gibt's sicher noch einiges zu verbessern.

    Vielen Dank für die Funktion. 🙂👍 Ich hatte es bis jetzt immer mit 2 push_backs gesehen und dachte es geht nicht anders.
    Ich brauchte auch so eine Split-Funktion für mein Programm und ich habe noch mit einem zusätzlichen Parameter festgelegt, wie leere Token behandelt werden. Und diese Abfrage hatte ich dann an 2 Stellen was ich nicht so gut fand. 🙂

    Aber was soll man denn da noch verbessern können? 😮 🙂



  • :)- schrieb:

    Aber was soll man denn da noch verbessern können? 😮 🙂

    Z.b. das er nicht in jedem Schleifendurchlauf sep.length() aufruft.
    Evtl. optimiert der Compiler das, evtl. auch nicht.



  • :)- schrieb:

    Aber was soll man denn da noch verbessern können? 😮 🙂

    Das war eher designtechnisch zu verstehen.. so ist die Beschränkung auf vector<string> z.B. nicht allzu hübsch, also:

    template <typename OutputIterator>
    void explode( OutputIterator it, string const& str, string const& sep )
    {
      const string::size_type sepLength = sep.length();
      string::size_type begin = 0, end;
      do {
        end = str.find(sep, begin);
        *it = str.substr(begin, end-begin);
        ++it;
        begin = end + sepLength;
      } while (end != string::npos);
    }
    
    void explode( vector<string>& res, string const& str, string const& sep )
    {
      explode(back_inserter< vector<string> >(res), str, sep);
    }
    

    Dann taucht natürlich die Frage auf wie mit leeren Tokens zu verfahren ist. Mehrere Separatoren? etc.

    Spinnt man das weiter wird man am Ende wohl wirklich bei boost::algorithm::split oder boost::tokenizer oder so ähnlich landen...


Anmelden zum Antworten