wake-up-neo.net

Teilen Sie einen String mit C++ 11

Was wäre die einfachste Methode, einen String mit C++ 11 zu teilen?

Ich habe die Methode gesehen, die von post verwendet wird, aber ich denke, dass es weniger wortreich sein sollte, dies unter Verwendung des neuen Standards zu tun.

Edit: Ich möchte als Ergebnis einen vector<string> haben und ein einzelnes Zeichen abgrenzen können.

46
Mark

std::regex_token_iterator führt eine generische Tokenisierung basierend auf einem regulären Ausdruck durch. Es kann oder kann nicht übertrieben sein, wenn Sie ein einzelnes Zeichen einfach aufteilen wollen, aber es funktioniert und ist nicht zu ausführlich:

std::vector<std::string> split(const string& input, const string& regex) {
    // passing -1 as the submatch index parameter performs splitting
    std::regex re(regex);
    std::sregex_token_iterator
        first{input.begin(), input.end(), re, -1},
        last;
    return {first, last};
}
57
JohannesD

Hier ist ein (möglicherweise weniger ausführlicher) Weg, den String zu teilen (basierend auf dem post von dir genannten).

#include <string>
#include <sstream>
#include <vector>
std::vector<std::string> split(const std::string &s, char delim) {
  std::stringstream ss(s);
  std::string item;
  std::vector<std::string> elems;
  while (std::getline(ss, item, delim)) {
    elems.Push_back(item);
    // elems.Push_back(std::move(item)); // if C++11 (based on comment from @mchiasson)
  }
  return elems;
}
18
Yaguang

Hier ein Beispiel für das Aufteilen einer Zeichenfolge und das Auffüllen eines Vektors mit den extrahierten Elementen mit boost.

#include <boost/algorithm/string.hpp>

std::string my_input("A,B,EE");
std::vector<std::string> results;

boost::algorithm::split(results, my_input, is_any_of(","));

assert(results[0] == "A");
assert(results[1] == "B");
assert(results[2] == "EE");
9
fduff

Eine andere Regex-Lösung inspiriert von anderen Antworten aber hoffentlich kürzer und einfacher zu lesen:

std::string s{"String to split here, and here, and here,..."};
std::regex regex{R"([\s,]+)"}; // split on space and comma
std::sregex_token_iterator it{s.begin(), s.end(), regex, -1};
std::vector<std::string> words{it, {}};
6
wally
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>


using namespace std;

vector<string> split(const string& str, int delimiter(int) = ::isspace){
  vector<string> result;
  auto e=str.end();
  auto i=str.begin();
  while(i!=e){
    i=find_if_not(i,e, delimiter);
    if(i==e) break;
    auto j=find_if(i,e, delimiter);
    result.Push_back(string(i,j));
    i=j;
  }
  return result;
}

int main(){
  string line;
  getline(cin,line);
  vector<string> result = split(line);
  for(auto s: result){
    cout<<s<<endl;
  }
}
4
chekkal

Meine Wahl ist boost::tokenizer, aber ich hatte keine schweren Aufgaben und teste mit riesigen Daten. Beispiel aus einem Boost-Dokument mit Lambda-Modifikation:

#include <iostream>
#include <boost/tokenizer.hpp>
#include <string>
#include <vector>

int main()
{
   using namespace std;
   using namespace boost;

   string s = "This is,  a test";
   vector<string> v;
   tokenizer<> tok(s);
   for_each (tok.begin(), tok.end(), [&v](const string & s) { v.Push_back(s); } );
   // result 4 items: 1)This 2)is 3)a 4)test
   return 0;
}
4
Torsten

Ich weiß nicht, ob dies weniger ausführlich ist, aber es ist vielleicht einfacher für diejenigen, die mehr Erfahrung in dynamischen Sprachen wie Javascript haben. Die einzige C++ 11-Funktion, die es verwendet, sind Lambdas.

#include <algorithm>
#include <string>
#include <cctype>
#include <iostream>
#include <vector>

int main()
{
  using namespace std;
  string s = "hello  how    are you won't you tell me your name";
  vector<string> tokens;
  string token;

  for_each(s.begin(), s.end(), [&](char c) {
    if (!isspace(c))
        token += c;
    else 
    {
        if (token.length()) tokens.Push_back(token);
        token.clear();
    }
  });
  if (token.length()) tokens.Push_back(token);

  return 0;
}
4
Faisal Vali

Das ist meine Antwort. Ausführlich, lesbar und effizient.

std::vector<std::string> tokenize(const std::string& s, char c) {
    auto end = s.cend();
    auto start = end;

    std::vector<std::string> v;
    for( auto it = s.cbegin(); it != end; ++it ) {
        if( *it != c ) {
            if( start == end )
                start = it;
            continue;
        }
        if( start != end ) {
            v.emplace_back(start, it);
            start = end;
        }
    }
    if( start != end )
        v.emplace_back(start, end);
    return v;
}
3
ymmt2005

Hier ist eine C++ 11-Lösung, die nur std :: string :: find () verwendet. Das Trennzeichen kann beliebig lang sein. Analysierte Token werden über einen Ausgabe-Iterator ausgegeben, der in meinem Code normalerweise ein std :: back_inserter ist.

Ich habe dies nicht mit UTF-8 getestet, aber ich gehe davon aus, dass es funktionieren sollte, solange Eingabe und Trennzeichen gültige UTF-8-Zeichenfolgen sind.

#include <string>

template<class Iter>
Iter splitStrings(const std::string &s, const std::string &delim, Iter out)
{
    if (delim.empty()) {
        *out++ = s;
        return out;
    }
    size_t a = 0, b = s.find(delim);
    for ( ; b != std::string::npos;
          a = b + delim.length(), b = s.find(delim, a))
    {
        *out++ = std::move(s.substr(a, b - a));
    }
    *out++ = std::move(s.substr(a, s.length() - a));
    return out;
}

Einige Testfälle:

void test()
{
    std::vector<std::string> out;
    size_t counter;

    std::cout << "Empty input:" << std::endl;        
    out.clear();
    splitStrings("", ",", std::back_inserter(out));
    counter = 0;        
    for (auto i = out.begin(); i != out.end(); ++i, ++counter) {
        std::cout << counter << ": " << *i << std::endl;
    }

    std::cout << "Non-empty input, empty delimiter:" << std::endl;        
    out.clear();
    splitStrings("Hello, world!", "", std::back_inserter(out));
    counter = 0;        
    for (auto i = out.begin(); i != out.end(); ++i, ++counter) {
        std::cout << counter << ": " << *i << std::endl;
    }

    std::cout << "Non-empty input, non-empty delimiter"
                 ", no delimiter in string:" << std::endl;        
    out.clear();
    splitStrings("abxycdxyxydefxya", "xyz", std::back_inserter(out));
    counter = 0;        
    for (auto i = out.begin(); i != out.end(); ++i, ++counter) {
        std::cout << counter << ": " << *i << std::endl;
    }

    std::cout << "Non-empty input, non-empty delimiter"
                 ", delimiter exists string:" << std::endl;        
    out.clear();
    splitStrings("abxycdxy!!xydefxya", "xy", std::back_inserter(out));
    counter = 0;        
    for (auto i = out.begin(); i != out.end(); ++i, ++counter) {
        std::cout << counter << ": " << *i << std::endl;
    }

    std::cout << "Non-empty input, non-empty delimiter"
                 ", delimiter exists string"
                 ", input contains blank token:" << std::endl;        
    out.clear();
    splitStrings("abxycdxyxydefxya", "xy", std::back_inserter(out));
    counter = 0;        
    for (auto i = out.begin(); i != out.end(); ++i, ++counter) {
        std::cout << counter << ": " << *i << std::endl;
    }

    std::cout << "Non-empty input, non-empty delimiter"
                 ", delimiter exists string"
                 ", nothing after last delimiter:" << std::endl;        
    out.clear();
    splitStrings("abxycdxyxydefxy", "xy", std::back_inserter(out));
    counter = 0;        
    for (auto i = out.begin(); i != out.end(); ++i, ++counter) {
        std::cout << counter << ": " << *i << std::endl;
    }

    std::cout << "Non-empty input, non-empty delimiter"
                 ", only delimiter exists string:" << std::endl;        
    out.clear();
    splitStrings("xy", "xy", std::back_inserter(out));
    counter = 0;        
    for (auto i = out.begin(); i != out.end(); ++i, ++counter) {
        std::cout << counter << ": " << *i << std::endl;
    }
}

Erwartete Ausgabe:

 Leere Eingabe: 
 0: 
 Nicht leere Eingabe, leeres Trennzeichen: 
 0: Hallo, Welt! 
 Nicht leere Eingabe, nicht leeres Trennzeichen, kein Trennzeichen in Zeichenfolge :
 0: abxycdxyxydefxya 
 Nicht leere Eingabe, nicht leere Trennzeichen, Trennzeichen ist vorhanden. 4: a 
 Nicht leere Eingabe, nicht leere Trennzeichen, Trennzeichen existiert Zeichenfolge, Eingabe enthält leeres Token: 
 0: ab 
 1: cd 
 2: 
 3: def 
4: a 
 Nicht leere Eingabe, nicht leere Trennzeichen, Trennzeichen existiert Zeichenfolge, nichts nach dem letzten Trennzeichen: 
 0: ab 
 1: cd 
 2: 
 3: def
 4: 
 Nicht leere Eingabe, nicht leere Trennzeichen, nur Trennzeichen ist vorhanden. String: 
 0: 
 1: 
1
villains
#include <string>
#include <vector>
#include <sstream>

inline vector<string> split(const string& s) {
    vector<string> result;
    istringstream iss(s);
    for (string s; iss >> s; )
        result.Push_back(s);
    return result;
}
0
Bill Moore