478 Stimmen

Wie kann ich eine Zeichenkette in C++ tokenisieren?

Java verfügt über eine praktische Split-Methode:

String str = "The quick brown fox";
String[] results = str.split(" ");

Gibt es eine einfache Möglichkeit, dies in C++ zu tun?

234 Stimmen

Ich kann nicht glauben, dass diese Routineaufgabe in C++ so viel Kopfzerbrechen macht

6 Stimmen

Seine nicht Kopfschmerzen in C + + - es gibt verschiedene Möglichkeiten, um es zu erreichen. Programmierer sind weniger bewusst, C + + als c # - seine über Marketing und Investitionen ... siehe dies für verschiedene C + + Optionen, um das gleiche zu erreichen: cplusplus.com/faq/sequenzen/strings/split

11 Stimmen

@hB0 gehen durch viele Fragen Antworten und immer noch nicht entscheiden, bedeutet, ist ein Kopfschmerz. die eine braucht, dass die Bibliothek, die andere ist nur für Leerzeichen, die andere nicht behandeln Leerzeichen.

86voto

KeithB Punkte 15939

Sie können Streams, Iteratoren und den Kopieralgorithmus verwenden, um dies ziemlich direkt zu tun.

#include <string>
#include <vector>
#include <iostream>
#include <istream>
#include <ostream>
#include <iterator>
#include <sstream>
#include <algorithm>

int main()
{
  std::string str = "The quick brown fox";

  // construct a stream from the string
  std::stringstream strstr(str);

  // use stream iterators to copy the stream to the vector as whitespace separated strings
  std::istream_iterator<std::string> it(strstr);
  std::istream_iterator<std::string> end;
  std::vector<std::string> results(it, end);

  // send the vector to stdout.
  std::ostream_iterator<std::string> oit(std::cout);
  std::copy(results.begin(), results.end(), oit);
}

77voto

w.b Punkte 10628

Eine Lösung mit regex_token_iterator s:

#include <iostream>
#include <regex>
#include <string>

using namespace std;

int main()
{
    string str("The quick brown fox");

    regex reg("\\s+");

    sregex_token_iterator iter(str.begin(), str.end(), reg, -1);
    sregex_token_iterator end;

    vector<string> vec(iter, end);

    for (auto a : vec)
    {
        cout << a << endl;
    }
}

50voto

Mr.Ree Punkte 8112

Nichts für ungut, Leute, aber für ein so einfaches Problem machen Sie sich zu viele Gedanken. Weg zu kompliziert. Es gibt viele Gründe für die Verwendung von Boost . Aber bei etwas so Einfachem ist es, als würde man eine Fliege mit einem 20#-Schlitten schlagen.

void
split( vector<string> & theStringVector,  /* Altered/returned value */
       const  string  & theString,
       const  string  & theDelimiter)
{
    UASSERT( theDelimiter.size(), >, 0); // My own ASSERT macro.

    size_t  start = 0, end = 0;

    while ( end != string::npos)
    {
        end = theString.find( theDelimiter, start);

        // If at end, use length=maxLength.  Else use length=end-start.
        theStringVector.push_back( theString.substr( start,
                       (end == string::npos) ? string::npos : end - start));

        // If at end, use start=maxSize.  Else use start=end+delimiter.
        start = (   ( end > (string::npos - theDelimiter.size()) )
                  ?  string::npos  :  end + theDelimiter.size());
    }
}

Zum Beispiel (für Dougs Fall),

#define SHOW(I,X)   cout << "[" << (I) << "]\t " # X " = \"" << (X) << "\"" << endl

int
main()
{
    vector<string> v;

    split( v, "A:PEP:909:Inventory Item", ":" );

    for (unsigned int i = 0;  i < v.size();   i++)
        SHOW( i, v[i] );
}

Und ja, wir könnten split() einen neuen Vektor zurückgeben lassen, anstatt einen zu übergeben. Es ist trivial zu wickeln und zu überladen. Aber je nachdem, was ich tue, finde ich es oft besser, bereits existierende Objekte wiederzuverwenden, als immer neue zu erstellen. (Solange ich nur nicht vergesse, den Vektor zwischendurch zu leeren!)

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

(Ursprünglich wollte ich eine Antwort auf Dougs Frage schreiben: C++ Strings Ändern und Extrahieren anhand von Trennzeichen (geschlossen) . Aber da Martin York diese Frage mit einem Hinweis hier drüben geschlossen hat... werde ich meinen Code einfach verallgemeinern).

39voto

Raz Punkte 1932

Boost hat eine starke Splitfunktion: boost::algorithm::split .

Beispielprogramm:

#include <vector>
#include <boost/algorithm/string.hpp>

int main() {
    auto s = "a,b, c ,,e,f,";
    std::vector<std::string> fields;
    boost::split(fields, s, boost::is_any_of(","));
    for (const auto& field : fields)
        std::cout << "\"" << field << "\"\n";
    return 0;
}

Ausgabe:

"a"
"b"
" c "
""
"e"
"f"
""

29voto

Parham Punkte 2547

Dies ist eine einfache STL-Lösung (~5 Zeilen!) mit std::find et std::find_first_not_of die Wiederholungen des Begrenzungszeichens (z. B. Leerzeichen oder Punkte) sowie führende und nachgestellte Begrenzungszeichen behandelt:

#include <string>
#include <vector>

void tokenize(std::string str, std::vector<string> &token_v){
    size_t start = str.find_first_not_of(DELIMITER), end=start;

    while (start != std::string::npos){
        // Find next occurence of delimiter
        end = str.find(DELIMITER, start);
        // Push back the token found into vector
        token_v.push_back(str.substr(start, end-start));
        // Skip all occurences of the delimiter to find new start
        start = str.find_first_not_of(DELIMITER, end);
    }
}

Probieren Sie es aus live ¡!

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X