wwrite warning una strings obsoleta from forbids dev converting conversión conversion constante constant cadena c++ string split c++11

warning - Dividir una cadena usando C++ 11



dev c++ warning deprecated conversion from string constant to char wwrite strings (10)

¿Cuál sería el método más sencillo para dividir una cadena usando c ++ 11?

He visto el método utilizado en esta post , pero creo que debería haber una manera menos detallada de hacerlo con el nuevo estándar.

Editar: me gustaría tener un vector<string> como resultado y ser capaz de delimitar en un solo carácter.


Aquí hay un ejemplo de dividir una cadena y poblar un vector con los elementos extraídos usando 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");


Aquí hay una manera (quizás menos detallada) de dividir una cadena (según la post que mencionaste).

#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; }


Aquí hay una solución C ++ 11 que usa solo std :: string :: find (). El delimitador puede tener cualquier cantidad de caracteres. Los tokens parsed se envían a través de un iterador de salida, que generalmente es un std :: back_inserter en mi código.

No he probado esto con UTF-8, pero espero que funcione siempre que la entrada y el delimitador sean cadenas válidas UTF-8.

#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; }

Algunos casos de prueba:

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; } }

Rendimiento esperado:

Empty input: 0: Non-empty input, empty delimiter: 0: Hello, world! Non-empty input, non-empty delimiter, no delimiter in string: 0: abxycdxyxydefxya Non-empty input, non-empty delimiter, delimiter exists string: 0: ab 1: cd 2: !! 3: def 4: a Non-empty input, non-empty delimiter, delimiter exists string, input contains blank token: 0: ab 1: cd 2: 3: def 4: a Non-empty input, non-empty delimiter, delimiter exists string, nothing after last delimiter: 0: ab 1: cd 2: 3: def 4: Non-empty input, non-empty delimiter, only delimiter exists string: 0: 1:


Esta es mi respuesta. Verboso, legible y eficiente.

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; }


Mi elección es boost::tokenizer pero no tuve ninguna tarea pesada y la prueba con gran cantidad de datos. Ejemplo de boost doc con modificación lambda:

#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; }


No sé si esto es menos detallado, pero podría ser más fácil asimilar a los más experimentados en lenguajes dinámicos como javascript. La única característica de C ++ 11 que utiliza es 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; }


Otra solución regex inspirada en otras respuestas, pero con suerte más corta y más fácil de leer:

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, {}};


std::regex_token_iterator realiza una tokenización genérica basada en una expresión regular. Puede o no ser excesivo para hacer divisiones simples en un solo carácter, pero funciona y no es demasiado detallado:

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}; }


#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; } }


#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; }