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?
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?
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;
}
}
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;
}
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{}
);
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 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.
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.
3 Stimmen
Mögliches Duplikat von Eine Zeichenkette in C++ aufteilen?
8 Stimmen
Warum muss in C++ alles ein Kampf sein?
2 Stimmen
C++ ist eine leistungsfähige Sprache, die keine Einheitslösung für die Zeichenkettenmanipulation bietet. Für diese Anwendung ist manchmal alles, was Sie wollen, das letzte Token oder die ersten paar Token, aber ein "Split" wird alles tokenisieren, ohne bedarfsorientierte Stopps. Unabhängig davon sind String-Operationen in jeder Sprache teuer, und deshalb hat sich der C++-Standard ausdrücklich gegen übermäßig vereinfachende Schnittstellen ausgesprochen, die die wahre Komplexität verbergen.
0 Stimmen
@JohnPhuNguyen:
a "split" will tokenize everything without any need-based stops
. Kein Scherz. Das ist genau das Verhalten, das erwünscht ist.1 Stimmen
Interessanterweise sind alle Antworten auf diese Frage auch Antworten auf
Why are Java and Python so much more popular than C++?
.1 Stimmen
@stackoverflowuser2010 Ich glaube, Sie haben den Punkt nicht verstanden. Ja, das ist genau das Verhalten, das bei einem einheitlichen Ansatz erwünscht ist, was ich auch gesagt habe. Und es ist relevant für die Antwort auf die Frage, warum es in Java einfacher zu machen ist als in C++. Die CPP-Standardbibliothek vermeidet explizit alle Komfortmethoden, die die algorithmische Komplexität abstrahieren - deshalb können One-Size-Fits-All-Methoden angeboten werden, werden aber nicht angeboten.
0 Stimmen
@JohnPhuNguyen: Ich verstehe nicht, was Sie meinen mit
one size fits all
. In dieser Frage gibt es nur eine Größe: Tokenize a string. Es gibt keine andere Größe.0 Stimmen
@stackoverflowuser2010 Was ich meine ist, dass die Tokenisierung eine teure Funktion ist, die oft generisch verwendet wird, auch wenn sie nicht benötigt wird. C++ fördert die Implementierung spezifischer Anwendungsfälle anstelle der Tokenisierung, da der eigentliche Akt der Tokenisierung selten benötigt wird. Es wird oft als Mittel verwendet, um etwas in einer Zeichenkette zu finden. Stattdessen bietet C++ (unter anderem) Regex-Matching, das zwar teuer ist, aber bei weitem nicht so teuer wie die String-Manipulation, die in Tokenizern stattfindet. Ja, ein Tokenizer wird leicht für jede Lösung passen, aber er ist selten die beste Lösung. C++ rät davon ab, diesen Weg zu gehen.
1 Stimmen
Eine Lösung für genau diese Frage scheint hier zu liegen: riptutorial.com/cplusplus/example/2148/tokenize