// Teach a man to fish and you feed him for a lifetime. //
// Unless he doesn't like sushi – then you also have to teach him to cook. //
Eine Textzeichenkette ist in eine Folge von Teilen zu zerlegen, zwischen denen jeweils eine feststehende Zeichenfolge zu finden ist. Aus
"1, 2, 3, 4, 5"
werden mit der Trennzeichenfolge ", " die 5 Teilketten
"1", "2", "3", "4", "5".
Die gewünschte Funktion split(text, separator) nimmt ein Leerzeichen als Standardtrenner.
#include <string> #include <vector> std::vector<std::string> split(std::string const& input, std::string const& separator = " ") { std::vector<std::string> result; std::string::size_type position, start = 0; while (std::string::npos != (position = input.find(separator, start))) { result.push_back(input.substr(start, position-start)); start = position + separator.size(); } result.push_back(input.substr(start)); return result; }
Eine Anzahl weiterer Lösungen findet sich auf Stackoverflow. Für einzelne Separatorzeichen aus einer Liste vgl. http://rosettacode.org/wiki/Tokenize_a_string#C.2B.2B .
Das Kopieren von Zeichenketten ist aufwendig.
Mit std::string_view wird jeweils nur ein Zeiger auf den Anfang und die Länge gespeichert.
Voraussetzung ist, dass die zu zerlegende Teilzettenkette mindestens solange existiert, wie per string_view darauf zugegriffen wird:
#include <string_view> // C++17 #include <vector> auto split(std::string_view input, std::string_view separator = " ") { std::vector<std::string_view> result; std::string_view::size_type position, start = 0; while (std::string_view::npos != (position = input.find(separator, start))) { result.push_back(input.substr(start, position-start)); start = position + separator.size(); } result.push_back(input.substr(start)); return result; }
Hier wird eine ganze Zeichenkette als Trenner erwartet.
In diesem Beispiel werden die Zeichenfolgen ", "
der Eingabe 1, 2, 3, 4, 5 als Trenner akzeptiert,
ein einzelnes Komma jedoch nicht:
#include <iostream> int main() { std::string line; while (std::getline(std::cin, line)) { for (auto part : split(line, ", ")) // C++11 { std::cout << "\'" << part << "\'\n"; } } return 0; }
Reguläre Ausdrücke geben mehr Möglichkeiten zur Beschreibung des Trenners.
Hier eine C++17-Variante mit string_view:
#include <iostream> #include <regex> #include <string_view> // adapted from: http://stackoverflow.com/a/28142357/831725 auto split(std::string_view input, std::string_view separator = "\\s+") { std::vector<std::string_view> result; std::regex rex(separator.begin(), separator.end()); std::cregex_token_iterator iter(input.begin(), input.end(), rex, -1); std::cregex_token_iterator end; // -1 : get stuff not matched by regex for (; iter != end; ++iter) { std::string_view::size_type numchars = iter->second - iter->first; result.push_back({iter->first, numchars}); } return result; } int main() { for (auto e : split("eins zwei drei ")) // Whitespaces als Trenner { std::cout << e << '\n'; } for (auto e : split("vier|fuenf:sechs,sieben", "[|:,]")) { std::cout << e << '\n'; } }