Diviser une chaîne en utilisant C ++ 11

Quelle serait la méthode la plus simple pour diviser une chaîne en utilisant c ++ 11?

J’ai vu la méthode utilisée par cet article , mais j’estime qu’il devrait y avoir une manière moins verbeuse de le faire en utilisant la nouvelle norme.

Edit: Je voudrais avoir un vector et pouvoir délimiter un seul caractère.

std::regex_token_iterator effectue une tokenisation générique basée sur une regex. Cela peut être ou non exagéré pour un simple fractionnement sur un seul caractère, mais cela fonctionne et n’est pas trop verbeux:

 std::vector split(const ssortingng& input, const ssortingng& 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}; } 

Voici un moyen (peut-être moins prolixe) de diviser la chaîne (en fonction du message que vous avez mentionné).

 #include  #include  #include  std::vector split(const std::ssortingng &s, char delim) { std::ssortingngstream ss(s); std::ssortingng item; std::vector 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; } 

Voici un exemple de division d’une chaîne et de remplissage d’un vecteur avec les éléments extraits à l’aide de boost .

 #include  std::ssortingng my_input("A,B,EE"); std::vector results; boost::algorithm::split(results, my_input, is_any_of(",")); assert(results[0] == "A"); assert(results[1] == "B"); assert(results[2] == "EE"); 

Je ne sais pas si cela est moins verbeux, mais il serait peut-être plus facile de chercher des personnes plus expérimentées dans des langages dynamics tels que le javascript. La seule fonctionnalité C ++ 11 utilisée est lambdas.

 #include  #include  #include  #include  #include  int main() { using namespace std; ssortingng s = "hello how are you won't you tell me your name"; vector tokens; ssortingng 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; } 

Mon choix est boost::tokenizer mais je n’ai pas eu de tâches lourdes et de tests avec des données énormes. Exemple de boost doc avec modification lambda:

 #include  #include  #include  #include  int main() { using namespace std; using namespace boost; ssortingng s = "This is, a test"; vector 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; } 
 #include  #include  #include  #include  using namespace std; vector split(const ssortingng& str, int delimiter(int) = ::isspace){ vector 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(ssortingng(i,j)); i=j; } return result; } int main(){ ssortingng line; getline(cin,line); vector result = split(line); for(auto s: result){ cout< 

Ceci est ma réponse. Verbose, lisible et efficace.

 std::vector tokenize(const std::ssortingng& s, char c) { auto end = s.cend(); auto start = end; std::vector 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; } 

Une autre solution de regex inspirée par d’autres réponses, mais plus courte et plus facile à lire:

 std::ssortingng s{"Ssortingng 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 words{it, {}}; 

Voici une solution C ++ 11 qui utilise uniquement std :: ssortingng :: find (). Le délimiteur peut contenir n’importe quel nombre de caractères. Les jetons analysés sont générés via un iterator de sortie, qui est généralement un std :: back_inserter dans mon code.

Je n’ai pas testé cela avec UTF-8, mais je pense qu’il devrait fonctionner tant que l’entrée et le délimiteur sont tous deux des chaînes UTF-8 valides.

 #include  template Iter splitSsortingngs(const std::ssortingng &s, const std::ssortingng &delim, Iter out) { if (delim.empty()) { *out++ = s; return out; } size_t a = 0, b = s.find(delim); for ( ; b != std::ssortingng::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; } 

Quelques cas de test:

 void test() { std::vector 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; } } 

Production attendue:

 Entrée vide:
 0: 
 Entrée non vide, délimiteur vide:
 0: Bonjour, monde!
 Entrée non vide, délimiteur non vide, pas de délimiteur dans la chaîne:
 0: abxycdxyxydefxya
 Entrée non vide, délimiteur non vide, délimiteur existant chaîne:
 0: ab
 1: cd
 2: !!
 3: def
 4: a
 Entrée non vide, délimiteur non vide, délimiteur existant, entrée contenant un jeton vide:
 0: ab
 1: cd
 2: 
 3: def
 4: a
 Entrée non vide, délimiteur non vide, délimiteur existant chaîne, rien après le dernier délimiteur:
 0: ab
 1: cd
 2: 
 3: def
 4: 
 Entrée non vide, délimiteur non vide, seul délimiteur existe chaîne:
 0: 
 1: 
 #include  #include  #include  inline vector split(const ssortingng& s) { vector result; issortingngstream iss(s); for (ssortingng s; iss >> s; ) result.push_back(s); return result; }