String teilen



  • und nicht int output[] sondern lieber std::vectorstd::string



  • Version 1 (stringstream)

    void split(string str,vector <string> &vec,char delemiter)
    {
    	stringstream sstr(str);
    	if(vec.size()) vector<string>().swap(vec);
    	while(getline(sstr,str,delemiter)) vec.push_back(str);
    }
    

    Version 2 (ohne stringstream geringfügig schneller)

    void split(const string &source,vector <string> &split,char delemiter)
    {
    	unsigned p(-1),o;
    	if(split.size()) vector<string>().swap(split);
    	do
    	{
    	o=++p;
    	p=source.find(delemiter,p);
    	split.push_back(source.substr(o,p-o));
    	}
    	while(p!=string::npos);
    }
    


  • da ist noch ein kleiner bug bzw. überbleibsel (int und nicht unsigned).

    void split(const string &source,vector <string> &split,char delemiter) 
    { 
        int p(-1),o; 
        if(split.size()) vector<string>().swap(split); 
        do 
        { 
        o=++p; 
        p=source.find(delemiter,p); 
        split.push_back(source.substr(o,p-o)); 
        } 
        while(p!=string::npos); 
    }
    


  • Ist das normal, dass man bei Iteratoren ein Assertion failed um die Ohren bekommt, sobald ein Iterator mal außerhalb seiner üblichen Umgebung ist?
    Das verhindert dann nämlich hier z.B. eine schöne Schleifenbedingung:
    (Ich hoffe mal ich übersehe da etwas..)

    void arnold(std::string::iterator first, std::string::iterator last, 
      char delim, std::vector<std::string>& output)
    {
      std::string::iterator it = std::find(first, last, delim);
      while (it != last)
      {
        output.push_back(std::string(first, it));
        first = it + 1;
        it = std::find(first, last, delim);
      }
      output.push_back(std::string(first, it));
    }
    
    int main()
    {
      std::string input = "12;33;34;22;11;823";
      std::vector<std::string> output;
      char delim = ';';
    
      arnold(input.begin(), input.end(), delim, output);
    
      for (std::vector<std::string>::iterator i = output.begin(); 
        i < output.end(); ++i)
      {
        std::cout << *i << std::endl;
      }
    }
    


  • boost::algorithm 😛



  • Hab ich neulich geschrieben, funktioniert auch mit std::vector und anderen Containern und du kannst noch eine Compare-Funktion angeben, falls du die Objekte nicht mit dem ==-Operator vergleichen willst: (Achtung, C++0x dabei!)

    //works for vectors as well as for strings
    //GetTokenized("a:bc:def::g", ':') == {"a", "bc", "def", "g"}
    template<typename T> bool DefaultCompareFunc(T const &first, T const &second)
    {
        return first == second;
    }
    
    template<typename T, typename... ExtraArgs, template<class T, class... ExtraArgs> class Container, typename FuncType>
        std::vector<Container<T> > GetTokenized(Container<T> const &in, T const &comp_value, FuncType comp_func)
    {
        std::vector<Container<T> > ret;
    
        typename Container<T>::const_iterator start_iter = in.begin(), end_iter = in.begin();
        while(end_iter != in.end())
        {
            if(comp_func(*end_iter, comp_value))
            {
                if(start_iter != end_iter)
                {
                    ret.push_back(Container<T>(start_iter, end_iter));
                }
                start_iter = end_iter;
                ++start_iter;
            }
            ++end_iter;
        }
    
        return ret;
    }
    
    template<typename T, typename... ExtraArgs, template<class T, class... ExtraArgs> class Container>
        std::vector<Container<T> > GetTokenized(Container<T> const &in, T const &comp_value)
    {
        return GetTokenized(in, comp_value, DefaultCompareFunc<T>);
    }
    


  • Wie wäre es mit boost::split?



  • Habe alle Versionen mal in Bezug auf Geschwindigkeit durchgetestet.
    Habe einen string mit 6 Token in einer fünf Millionen! Loop zerlegt.(ich weiss das ist ein sehr realitätsfremdes Beispiel)
    1. vector füllen über string::find und substr. (ca. 31 Sek.)
    2. vector füllen über algorithm::find und string::iterator (ca. 41 Sek.)
    3. vector füllen über stringstream (ca. 51 Sek.)
    4. vector füllen über boost::split (ca. 73 Sek.)
    Überrascht hat mich eigentlich nur das Ergebnis von boost::split.
    Die stringstream Variante wird wohl durch das kopieren des strings in den stream ausgebremst.



  • Danke ich konnte das Problem jetzt lösen.
    Nun bin ich an dem Problem angelangt das ich den vector<string> nicht in Integer convertiert kriege.
    Mit atoi gehts nicht. Hat irgendjemand dazu auch eine Idee?

    Vielen Dank.



  • for(int i = 0; i < bis.size(); i++) 
    {      
    	 output.push_back( atoi( bis.at(i).c_str() ) ); 
    }
    

    Hab es geschafft den String in integer zu kovertieren, danke



  • Wenn du eh Zahlen haben möchtest, mach es doch in einem Rutsch.

    void arnold(const char *s, std::vector<int>& output)
    {
      const char *p = s - 1;
      s += std::strlen(s);
      while (p < s)
        output.push_back(std::strtol(p + 1, const_cast<char**>(&p), 10));
    }
    

    Und wenn du jetzt als "delim" ein einfaches Leerzeichen nimmst, kannst du dir sogar das hässliche p + 1 sparen.



  • @cookie: Was soll denn diese hässliche C-Lösung hier bringen? Wenn schon, dann bitte richtig:

    void arnold(const string& s,vector<int>& out)
    {
      stringstream str(s);
      int val;
      while(str>>val)
      {
        str.get();//zum Verarbeiten des Trennzeichens
        out.push_back(val);
      }
    }
    

    (und bestimmt findet noch jemand eine Lösung mit std::copy() und Stream-Iteratoren :D)



  • Ist das gemogelt?

    vector<int> arnold(string input)
    {
    	vector<int> result;
    	replace(input.begin(), input.end(), ';', ' ');
    	stringstream stream(input);
    	copy(istream_iterator<int>(stream), istream_iterator<int>(), back_inserter(result));
    	return result;
    }
    


  • Für sowas ist das zuviel overhead ...



  • 372368 schrieb:

    Für sowas ist das zuviel overhead ...

    Inwiefern?



  • CStoll schrieb:

    @cookie: Was soll denn diese hässliche C-Lösung hier bringen?

    Nachdem er ja eh schon .c_str() genutzt hat, war mir das const char* jetzt auch recht. Und nachdem ich leider festellen musste, dass die C++ Streams einfach unfassbar langsam sind, nutze ich strtol() sobald man sehr viele Zahlen umwandeln muss. Es wird nicht unübersichtlicher und die Streams bieten mir auch keinen erkennbaren Vorteil.
    (Deine Lösung braucht auf meinem System z.B. ~25 mal so lange wie meine.)



  • cooky451 schrieb:

    (Deine Lösung braucht auf meinem System z.B. ~25 mal so lange wie meine.)

    Das glaub ich dir nicht so recht. Wie sieht dein Testprogramm aus?



  • Michael E. schrieb:

    cooky451 schrieb:

    (Deine Lösung braucht auf meinem System z.B. ~25 mal so lange wie meine.)

    Das glaub ich dir nicht so recht. Wie sieht dein Testprogramm aus?

    Ist doch Standard.
    ifstreams schaffen es bei mir teilweise nichtmal den Plattencontroller auszulasten (Raid 0 mit 2 Platten), langsamer wie ne HDD - das muss man erstmal schaffen.



  • cooky451 schrieb:

    CStoll schrieb:

    @cookie: Was soll denn diese hässliche C-Lösung hier bringen?

    Nachdem er ja eh schon .c_str() genutzt hat, war mir das const char* jetzt auch recht.

    Na gut, aber warum dann nicht gleich noch strtok() reinbringen 😃
    Btw, ich wollte nicht unbedingt eine schnelle Lösung, sondern eine elegante. Und da ich aktuell gar nicht mehr mit C++ arbeite, hätte ich im produktiven Einsatz vermutlich sowas geschrieben:

    Function: Arnold
      Description: Split a Semicolon-seperated List into its components
      Return Type:
        Number:
      Parameters:
        String: pIn
        Receive Number: paOut[*]
      Static Variables:
      Local Variables:
        Number: count
        Number: index
        String: aData[*]
      Actions
        Set count = SalStrTokenize( pIn, '', ';', aData )
        Set index = 0
        While index<count
          Set paOut[index] = SalStrToNumber( aData[i] )
          Set index = index+1
        Return count
    

    PS @Michael: Nein, die Lösung finde ich nicht als gemogelt 😃



  • Ich komm auf Faktor 6. Deshalb würd ich gern mal sehen, was cooky falsch macht.


Anmelden zum Antworten