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?
Adam Pierce's Antwort bietet einen handgesponnenen Tokenizer, der eine const char*
. Bei Iteratoren ist es etwas problematischer, weil Inkrementierung einer string
der End-Iterator ist undefiniert . Angesichts der Tatsache, dass string str{ "The quick brown fox" }
können wir dies sicherlich erreichen:
auto start = find(cbegin(str), cend(str), ' ');
vector<string> tokens{ string(cbegin(str), start) };
while (start != cend(str)) {
const auto finish = find(++start, cend(str), ' ');
tokens.push_back(string(start, finish));
start = finish;
}
Wenn Sie die Komplexität abstrahieren wollen, indem Sie Standardfunktionen verwenden, wie On Freund schlägt vor strtok
ist eine einfache Option:
vector<string> tokens;
for (auto i = strtok(data(str), " "); i != nullptr; i = strtok(nullptr, " ")) tokens.push_back(i);
Wenn Sie keinen Zugang zu C++17 haben, müssen Sie Folgendes ersetzen data(str)
wie in diesem Beispiel: http://ideone.com/8kAGoa
Dies wird in dem Beispiel jedoch nicht gezeigt, strtok
müssen nicht für jedes Token das gleiche Trennzeichen verwenden. Neben diesem Vorteil gibt es jedoch auch einige Nachteile:
strtok
kann nicht für mehrere Personen verwendet werden strings
zur gleichen Zeit: Entweder ein nullptr
muss übergeben werden, um die Tokenisierung des aktuellen string
oder eine neue char*
tokenize übergeben werden (es gibt einige nicht standardisierte Implementierungen, die dies jedoch unterstützen, wie z.B.: strtok_s
)strtok
kann nicht auf mehreren Threads gleichzeitig verwendet werden (dies kann jedoch z. B. durch die Implementierung festgelegt werden: Die Implementierung von Visual Studio ist thread-sicher )strtok
string
der es betrieben wird, so dass es nicht verwendet werden kann bei const string
s, const char*
s oder wörtliche Zeichenketten, um diese mit strtok
oder zum Betrieb einer string
deren Inhalt bewahrt werden muss, str
kopiert werden müsste, dann könnte die Kopie bearbeitet werdenc++20 versorgt uns mit split_view
Zeichenketten auf nicht-destruktive Weise tokenisieren: https://topanswers.xyz/cplusplus?q=749#a874
Die bisherigen Methoden können keine tokenisierte vector
in-place, d.h. ohne sie in eine Hilfsfunktion zu abstrahieren, können sie nicht initialisiert werden const vector<string> tokens
. Diese Funktionalität und die Fähigkeit zu akzeptieren cualquier Leerraumbegrenzer kann mit einem istream_iterator
. Zum Beispiel gegeben: const string str{ "The quick \tbrown \nfox" }
können wir dies tun:
istringstream is{ str };
const vector<string> tokens{ istream_iterator<string>(is), istream_iterator<string>() };
Die erforderliche Konstruktion eines istringstream
Diese Option ist mit weitaus höheren Kosten verbunden als die beiden vorangegangenen Optionen, die sich jedoch in der Regel in den Kosten für string
Zuweisung.
Wenn keine der oben genannten Optionen flexibel genug für Ihre Tokenisierungsanforderungen ist, ist die flexibelste Option die Verwendung einer regex_token_iterator
Natürlich bringt diese Flexibilität auch höhere Kosten mit sich, aber auch diese sind wahrscheinlich in den Kosten versteckt. string
Verteilungskosten. Nehmen wir zum Beispiel an, wir wollen auf der Basis von nicht-abgeschnittenen Kommas tokenisieren, die ebenfalls Leerraum fressen, und geben die folgende Eingabe ein: const string str{ "The ,qu\\,ick ,\tbrown, fox" }
können wir dies tun:
const regex re{ "\\s*((?:[^\\\\,]|\\\\.)*?)\\s*(?:,|$)" };
const vector<string> tokens{ sregex_token_iterator(cbegin(str), cend(str), re, 1), sregex_token_iterator() };
MFC/ATL hat einen sehr guten Tokenizer. Von MSDN:
CAtlString str( "%First Second#Third" );
CAtlString resToken;
int curPos= 0;
resToken= str.Tokenize("% #",curPos);
while (resToken != "")
{
printf("Resulting token: %s\n", resToken);
resToken= str.Tokenize("% #",curPos);
};
Output
Resulting Token: First
Resulting Token: Second
Resulting Token: Third
Sie können einfach eine Bibliothek für reguläre Ausdrücke und lösen das Problem mit regulären Ausdrücken.
Ausdruck verwenden ( \w +) und die Variable in \1 (oder $1, je nach der Bibliotheksimplementierung der regulären Ausdrücke).
Für einfache Dinge verwende ich einfach das Folgende:
unsigned TokenizeString(const std::string& i_source,
const std::string& i_seperators,
bool i_discard_empty_tokens,
std::vector<std::string>& o_tokens)
{
unsigned prev_pos = 0;
unsigned pos = 0;
unsigned number_of_tokens = 0;
o_tokens.clear();
pos = i_source.find_first_of(i_seperators, pos);
while (pos != std::string::npos)
{
std::string token = i_source.substr(prev_pos, pos - prev_pos);
if (!i_discard_empty_tokens || token != "")
{
o_tokens.push_back(i_source.substr(prev_pos, pos - prev_pos));
number_of_tokens++;
}
pos++;
prev_pos = pos;
pos = i_source.find_first_of(i_seperators, pos);
}
if (prev_pos < i_source.length())
{
o_tokens.push_back(i_source.substr(prev_pos));
number_of_tokens++;
}
return number_of_tokens;
}
Feiger Haftungsausschluss: Ich schreibe Echtzeit-Datenverarbeitungssoftware, bei der die Daten über Binärdateien, Sockets oder einen API-Aufruf (E/A-Karten, Kameras) eingehen. Ich verwende diese Funktion nie für etwas Komplizierteres oder Zeitkritischeres als das Einlesen externer Konfigurationsdateien beim Starten.
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