namespace cpp

C++ lernen, kennen, anwenden

Benutzer-Werkzeuge

Webseiten-Werkzeuge


howto:split_string

Text mit Trennfolgen zergliedern

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.

Aufgabe

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.

Ein Ansatz in C++98

split.cpp
#include <string>
#include <vector>
 
std::vector<std::string> 
split(const std::string& input, const std::string& 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 .

Leichtgewichtiger in C++17

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:

split_sv.cpp
#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 als Trenner

Reguläre Ausdrücke geben mehr Möglichkeiten zur Beschreibung des Trenners. Hier eine C++17-Variante mit string_view:

split_regex_sv.cpp
#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';
    }
}
howto/split_string.txt · Zuletzt geändert: 2017-01-29 15:58 (Externe Bearbeitung)