it-swarm.com.de

C++ - Zeichenfolge durch Regex aufteilen

Ich möchte std::string durch regex aufteilen.

Ich habe einige Lösungen in Stackoverflow gefunden, aber die meisten von ihnen teilen den String nach einzelnen Leerzeichen auf oder verwenden externe Bibliotheken wie boost.

Ich kann keinen Boost verwenden.

Ich möchte Zeichenfolge durch regex - "\\s+" teilen.

Ich verwende diese g ++ - Version g++ (Debian 4.4.5-8) 4.4.5 und ich kann kein Upgrade durchführen.

13

Sie müssen keine regulären Ausdrücke verwenden, wenn Sie eine Zeichenfolge nur durch mehrere Leerzeichen aufteilen möchten. Das Schreiben Ihrer eigenen Regex-Bibliothek ist für etwas so einfaches übertrieben.

Die Antwort, mit der Sie in Ihren Kommentaren verlinkt haben, Eine Zeichenfolge in C++ teilen? , kann leicht geändert werden, sodass keine leeren Elemente enthalten sind, wenn mehrere Leerzeichen vorhanden sind. 

std::vector<std::string> &split(const std::string &s, char delim,std::vector<std::string> &elems) {
    std::stringstream ss(s);
    std::string item;
    while (std::getline(ss, item, delim)) {
        if (item.length() > 0) {
            elems.Push_back(item);  
        }
    }
    return elems;
}


std::vector<std::string> split(const std::string &s, char delim) {
    std::vector<std::string> elems;
    split(s, delim, elems);
    return elems;
}

Wenn Sie item.length() > 0 überprüfen, bevor Sie item auf den elems-Vektor setzen, erhalten Sie keine zusätzlichen Elemente mehr, wenn Ihre Eingabe mehrere Trennzeichen (Leerzeichen in Ihrem Fall) enthält.

8
shf301
std::regex rgx("\\s+");
std::sregex_token_iterator iter(string_to_split.begin(),
    string_to_split.end(),
    rgx,
    -1);
std::sregex_token_iterator end;
for ( ; iter != end; ++iter)
    std::cout << *iter << '\n';

Der -1 ist hier der Schlüssel: Wenn der Iterator erstellt wird, zeigt der Iterator auf den Text, der vor der Übereinstimmung steht, und nach jedem Inkrement zeigt der Iterator auf den Text, der auf die vorherige Übereinstimmung folgte.

Wenn Sie nicht über C++ 11 verfügen, sollte dasselbe mit TR1 oder (möglicherweise mit geringfügigen Änderungen) mit Boost funktionieren.

38
Pete Becker

Um die Antwort von @Pete Becker zu erweitern, gebe ich ein Beispiel für die Funktion resplit, mit der Text mit regexp aufgeteilt werden kann:

  std::vector<std::string>
  resplit(const std::string & s, std::string rgx_str = "\\s+") {


      std::vector<std::string> elems;

      std::regex rgx (rgx_str);

      std::sregex_token_iterator iter(s.begin(), s.end(), rgx, -1);
      std::sregex_token_iterator end;

      while (iter != end)  {
          //std::cout << "S43:" << *iter << std::endl;
          elems.Push_back(*iter);
          ++iter;
      }

      return elems;

  }

Das funktioniert wie folgt:

   string s1 = "first   second third    ";
   vector<string> v22 = my::resplit(s1);

   for (const auto & e: v22) {
       cout <<"Token:" << e << endl;
   }


   //Token:first
   //Token:second
   //Token:third


   string s222 = "first|second:third,forth";
   vector<string> v222 = my::resplit(s222, "[|:,]");

   for (const auto & e: v222) {
       cout <<"Token:" << e << endl;
   }


   //Token:first
   //Token:second
   //Token:third
   //Token:forth
7
Marcin
string s = "foo bar  baz";
regex e("\\s+");
regex_token_iterator<string::iterator> i(s.begin(), s.end(), e, -1);
regex_token_iterator<string::iterator> end;
while (i != end)
   cout << " [" << *i++ << "]";

druckt [foo] [bar] [baz]

1
solstice333