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.

194voto

Ferruccio Punkte 96076

En Boost-Tokenizer Klasse kann diese Art von Dingen recht einfach machen:

#include <iostream>
#include <string>
#include <boost/foreach.hpp>
#include <boost/tokenizer.hpp>

using namespace std;
using namespace boost;

int main(int, char**)
{
    string text = "token, test   string";

    char_separator<char> sep(", ");
    tokenizer< char_separator<char> > tokens(text, sep);
    BOOST_FOREACH (const string& t, tokens) {
        cout << t << "." << endl;
    }
}

Aktualisiert für C++11:

#include <iostream>
#include <string>
#include <boost/tokenizer.hpp>

using namespace std;
using namespace boost;

int main(int, char**)
{
    string text = "token, test   string";

    char_separator<char> sep(", ");
    tokenizer<char_separator<char>> tokens(text, sep);
    for (const auto& t : tokens) {
        cout << t << "." << endl;
    }
}

183voto

Adam Pierce Punkte 32051

Hier ist ein ganz einfaches Beispiel:

#include <vector>
#include <string>
using namespace std;

vector<string> split(const char *str, char c = ' ')
{
    vector<string> result;

    do
    {
        const char *begin = str;

        while(*str != c && *str)
            str++;

        result.push_back(string(begin, str));
    } while (0 != *str++);

    return result;
}

177voto

Konrad Rudolph Punkte 503837

Die Algorithmen der C++-Standardbibliothek basieren fast durchgängig auf Iteratoren und nicht auf konkreten Containern. Das macht es leider schwierig, eine Java-ähnliche split Funktion in der C++-Standardbibliothek, auch wenn niemand behauptet, dass dies praktisch wäre. Aber was wäre ihr Rückgabetyp? std::vector<std::basic_string<…>> ? Vielleicht, aber dann sind wir gezwungen, (potenziell redundante und kostspielige) Zuweisungen vorzunehmen.

Stattdessen bietet C++ eine Fülle von Möglichkeiten zur Aufteilung von Zeichenketten auf der Grundlage beliebig komplexer Begrenzungszeichen, aber keine davon ist so gut gekapselt wie in anderen Sprachen. Die zahlreichen Möglichkeiten ganze Blogposts füllen .

Am einfachsten ist die Iteration mit std::string::find bis Sie auf std::string::npos und extrahieren Sie den Inhalt mit std::string::substr .

Eine flüssigere (und idiomatischere, aber einfachere) Version für die Aufteilung auf Whitespace würde eine std::istringstream :

auto iss = std::istringstream{"The quick brown fox"};
auto str = std::string{};

while (iss >> str) {
    process(str);
}

Verwendung von std::istream_iterator s kann der Inhalt des String-Streams auch in einen Vektor kopiert werden, indem sein Iterator-Range-Konstruktor verwendet wird.

Mehrere Bibliotheken (wie z.B. Boost.Tokenizer ) bieten spezielle Tokenisers an.

Fortgeschrittenere Aufteilungen erfordern reguläre Ausdrücke. C++ bietet die std::regex_token_iterator insbesondere zu diesem Zweck:

auto const str = "The quick brown fox"s;
auto const re = std::regex{R"(\s+)"};
auto const vec = std::vector<std::string>(
    std::sregex_token_iterator{begin(str), end(str), re, -1},
    std::sregex_token_iterator{}
);

149voto

user35978 Punkte 2212

Eine weitere schnelle Möglichkeit ist die Verwendung von getline . Etwa so:

stringstream ss("bla bla");
string s;

while (getline(ss, s, ' ')) {
 cout << s << endl;
}

Wenn Sie möchten, können Sie eine einfache split() Methode, die eine vector<string> das ist wirklich nützlich ist.

119voto

Mark Punkte 9728

Verwenden Sie strtok. Meiner Meinung nach gibt es keine Notwendigkeit, eine Klasse rund um Tokenisierung zu bauen, es sei denn, strtok bietet Ihnen nicht, was Sie brauchen. Vielleicht nicht, aber in über 15 Jahren, in denen ich verschiedenen Parsing-Code in C und C++ geschrieben habe, habe ich immer strtok verwendet. Hier ist ein Beispiel

char myString[] = "The quick brown fox";
char *p = strtok(myString, " ");
while (p) {
    printf ("Token: %s\n", p);
    p = strtok(NULL, " ");
}

Ein paar Vorbehalte (die Ihren Bedürfnissen vielleicht nicht entsprechen). Die Zeichenkette wird dabei "zerstört", d. h. EOS-Zeichen werden an den Begrenzungsstellen inline platziert. Für die korrekte Verwendung müssen Sie möglicherweise eine nicht-konstante Version der Zeichenkette erstellen. Sie können auch die Liste der Begrenzungszeichen beim Parsen ändern.

Meiner Meinung nach ist der obige Code viel einfacher und benutzerfreundlicher als eine eigene Klasse dafür zu schreiben. Für mich ist dies eine der Funktionen, die die Sprache zur Verfügung stellt, und sie macht es gut und sauber. Es ist einfach eine "C-basierte" Lösung. Es ist angemessen, es ist einfach, und man muss nicht viel zusätzlichen Code schreiben :-)

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