La forma más elegante de repetir las palabras de una cadena

¿Cuál es la forma más elegante de iterar las palabras de una cadena? Se puede suponer que la cadena está compuesta de palabras separadas por espacios en blanco.

Tenga en cuenta que no estoy interesado en las funciones de cadena C o ese tipo de manipulación / acceso de caracteres. Además, dé prioridad a la elegancia sobre la eficiencia en su respuesta.

La mejor solución que tengo ahora es:

#include  #include  #include  using namespace std; int main() { string s = "Somewhere down the road"; istringstream iss(s); do { string subs; iss >> subs; cout << "Substring: " << subs << endl; } while (iss); } 

Por lo que vale, esta es otra forma de extraer tokens de una cadena de entrada, confiando solo en las instalaciones de biblioteca estándar. Es un ejemplo del poder y la elegancia detrás del diseño del STL.

 #include  #include  #include  #include  #include  int main() { using namespace std; string sentence = "And I feel fine..."; istringstream iss(sentence); copy(istream_iterator(iss), istream_iterator(), ostream_iterator(cout, "\n")); } 

En lugar de copiar los tokens extraídos a una secuencia de salida, se pueden insertar en un contenedor, utilizando el mismo algoritmo de copy genérica.

 vector tokens; copy(istream_iterator(iss), istream_iterator(), back_inserter(tokens)); 

… o crea el vector directamente:

 vector tokens{istream_iterator{iss}, istream_iterator{}}; 

Yo uso esto para dividir la cadena por un delimitador. El primero pone los resultados en un vector preconstruido, el segundo devuelve un nuevo vector.

 #include  #include  #include  #include  template void split(const std::string &s, char delim, Out result) { std::stringstream ss(s); std::string item; while (std::getline(ss, item, delim)) { *(result++) = item; } } std::vector split(const std::string &s, char delim) { std::vector elems; split(s, delim, std::back_inserter(elems)); return elems; } 

Tenga en cuenta que esta solución no omite tokens vacíos, por lo que lo siguiente encontrará 4 elementos, uno de los cuales está vacío:

 std::vector x = split("one:two::three", ':'); 

Una posible solución usando Boost podría ser:

 #include  std::vector strs; boost::split(strs, "string to split", boost::is_any_of("\t ")); 

Este enfoque podría ser aún más rápido que el enfoque de stringstream . Y dado que se trata de una función de plantilla genérica, puede utilizarse para dividir otros tipos de cadenas (wchar, etc. o UTF-8) utilizando todo tipo de delimitadores.

Ver la documentación para más detalles.

 #include  #include  #include  int main() { std::string str("Split me by whitespaces"); std::string buf; // Have a buffer string std::stringstream ss(str); // Insert the string into a stream std::vector tokens; // Create vector to hold our words while (ss >> buf) tokens.push_back(buf); return 0; } 

Para aquellos con los que no se siente bien sacrificar toda la eficiencia por el tamaño del código y ver “eficiente” como un tipo de elegancia, lo siguiente debería alcanzar un punto óptimo (y creo que la clase de contenedor de plantilla es una adición asombrosamente elegante):

 template < class ContainerT > void tokenize(const std::string& str, ContainerT& tokens, const std::string& delimiters = " ", bool trimEmpty = false) { std::string::size_type pos, lastPos = 0, length = str.length(); using value_type = typename ContainerT::value_type; using size_type = typename ContainerT::size_type; while(lastPos < length + 1) { pos = str.find_first_of(delimiters, lastPos); if(pos == std::string::npos) { pos = length; } if(pos != lastPos || !trimEmpty) tokens.push_back(value_type(str.data()+lastPos, (size_type)pos-lastPos )); lastPos = pos + 1; } } 

Normalmente elijo usar std::vector como mi segundo parámetro ( ContainerT ) ... pero list<> es mucho más rápido que vector<> cuando no se necesita acceso directo, e incluso se puede crear su propia clase de cadena y usar algo como std::list donde subString no hace ninguna copia para incrementos de velocidad increíbles.

Es más del doble de rápido que el token más rápido en esta página y casi 5 veces más rápido que otros. Además, con los tipos de parámetros perfectos, puede eliminar todas las cadenas y copias de lista para aumentos de velocidad adicionales.

Además, no hace el retorno de resultados (extremadamente ineficiente), sino que pasa los tokens como referencia, lo que también te permite crear tokens usando múltiples llamadas si así lo deseas.

Por último, le permite especificar si desea recortar tokens vacíos de los resultados a través de un último parámetro opcional.

Todo lo que necesita es std::string ... el rest es opcional. No usa streams o la biblioteca de boost, pero es lo suficientemente flexible como para poder aceptar algunos de estos tipos foráneos de forma natural.

Aquí hay otra solución. Es compacto y razonablemente eficiente:

 std::vector split(const std::string &text, char sep) { std::vector tokens; std::size_t start = 0, end = 0; while ((end = text.find(sep, start)) != std::string::npos) { tokens.push_back(text.substr(start, end - start)); start = end + 1; } tokens.push_back(text.substr(start)); return tokens; } 

Puede ser templado fácilmente para manejar separadores de cuerdas, cuerdas anchas, etc.

Tenga en cuenta que dividir "" da como resultado una sola cadena vacía y dividir "," (es decir, sep) da como resultado dos cadenas vacías.

También se puede expandir fácilmente para omitir tokens vacíos:

 std::vector split(const std::string &text, char sep) { std::vector tokens; std::size_t start = 0, end = 0; while ((end = text.find(sep, start)) != std::string::npos) { if (end != start) { tokens.push_back(text.substr(start, end - start)); } start = end + 1; } if (end != start) { tokens.push_back(text.substr(start)); } return tokens; } 

Si desea dividir una cadena en múltiples delimitadores mientras omite tokens vacíos, esta versión puede ser utilizada:

 std::vector split(const std::string& text, const std::string& delims) { std::vector tokens; std::size_t start = text.find_first_not_of(delims), end = 0; while((end = text.find_first_of(delims, start)) != std::string::npos) { tokens.push_back(text.substr(start, end - start)); start = text.find_first_not_of(delims, end); } if(start != std::string::npos) tokens.push_back(text.substr(start)); return tokens; } 

Esta es mi forma favorita de iterar a través de una cadena. Puedes hacer lo que quieras por palabra.

 string line = "a line of text to iterate through"; string word; istringstream iss(line, istringstream::in); while( iss >> word ) { // Do something on `word` here... } 

Esto es similar a la pregunta de desbordamiento de stack ¿ Cómo puedo tokenizar una cadena en C ++? .

 #include  #include  #include  using namespace std; using namespace boost; int main(int argc, char** argv) { string text = "token test\tstring"; char_separator sep(" \t"); tokenizer> tokens(text, sep); for (const string& t : tokens) { cout << t << "." << endl; } } 

Me gusta lo siguiente porque pone los resultados en un vector, admite una cadena como un delim y le da control sobre mantener los valores vacíos. Pero, no se ve tan bien entonces.

 #include  #include  #include  #include  #include  using namespace std; vector split(const string& s, const string& delim, const bool keep_empty = true) { vector result; if (delim.empty()) { result.push_back(s); return result; } string::const_iterator substart = s.begin(), subend; while (true) { subend = search(substart, s.end(), delim.begin(), delim.end()); string temp(substart, subend); if (keep_empty || !temp.empty()) { result.push_back(temp); } if (subend == s.end()) { break; } substart = subend + delim.size(); } return result; } int main() { const vector words = split("So close no matter how far", " "); copy(words.begin(), words.end(), ostream_iterator(cout, "\n")); } 

Por supuesto, Boost tiene una split() que funciona parcialmente así. Y, si por ‘espacio en blanco’, realmente quiere decir cualquier tipo de espacio en blanco, usar la división de Boost con is_any_of() funciona muy bien.

El STL ya no tiene dicho método disponible.

Sin embargo, puede usar la strtok() std::string::c_str() C utilizando el miembro std::string::c_str() o puede escribir la suya propia. Aquí hay una muestra de código que encontré después de una búsqueda rápida en Google ( “STL string split” ):

 void Tokenize(const string& str, vector& tokens, const string& delimiters = " ") { // Skip delimiters at beginning. string::size_type lastPos = str.find_first_not_of(delimiters, 0); // Find first "non-delimiter". string::size_type pos = str.find_first_of(delimiters, lastPos); while (string::npos != pos || string::npos != lastPos) { // Found a token, add it to the vector. tokens.push_back(str.substr(lastPos, pos - lastPos)); // Skip delimiters. Note the "not_of" lastPos = str.find_first_not_of(delimiters, pos); // Find next "non-delimiter" pos = str.find_first_of(delimiters, lastPos); } } 

Tomado de: http://oopweb.com/CPP/Documents/CPPHOWTO/Volume/C++Programming-HOWTO-7.html

Si tiene preguntas sobre la muestra del código, deje un comentario y lo explicaré.

Y solo porque no implementa un typedef llamado iterador o sobrecarga, el operador << no significa que es un código incorrecto. Uso las funciones C con bastante frecuencia. Por ejemplo, printf y scanf son más rápidos que std::cin y std::cout (significativamente), la syntax fopen es mucho más amigable para los tipos binarios, y también tienden a producir EXEs más pequeños.

No se vendan en este trato de "Elegancia sobre el rendimiento" .

Aquí hay una función dividida que:

  • es genérico
  • usa C ++ estándar (sin boost)
  • acepta múltiples delimitadores
  • ignora tokens vacíos (puede cambiarse fácilmente)

     template vector split(const T & str, const T & delimiters) { vector v; typename T::size_type start = 0; auto pos = str.find_first_of(delimiters, start); while(pos != T::npos) { if(pos != start) // ignore empty tokens v.emplace_back(str, start, pos - start); start = pos + 1; pos = str.find_first_of(delimiters, start); } if(start < str.length()) // ignore trailing delimiter v.emplace_back(str, start, str.length() - start); // add what's left of the string return v; } 

Ejemplo de uso:

  vector v = split("Hello, there; World", ";,"); vector v = split(L"Hello, there; World", L";,"); 

Tengo una solución de 2 líneas para este problema:

 char sep = ' '; std::string s="1 This is an example"; for(size_t p=0, q=0; p!=s.npos; p=q) std::cout << s.substr(p+(p!=0), (q=s.find(sep, p+1))-p-(p!=0)) << std::endl; 

Entonces, en lugar de imprimir, puedes ponerlo en un vector.

Otra forma más flexible y rápida

 template void tokenize(Operator& op, const char* input, const char* delimiters) { const char* s = input; const char* e = s; while (*e != 0) { e = s; while (*e != 0 && strchr(delimiters, *e) == 0) ++e; if (e - s > 0) { op(s, e - s); } s = e + 1; } } 

Para usarlo con un vector de cadenas (Editar: Como alguien señaló que no debía heredar clases STL … hrmf;)):

 template class Appender { public: Appender(ContainerType& container) : container_(container) {;} void operator() (const char* s, unsigned length) { container_.push_back(std::string(s,length)); } private: ContainerType& container_; }; std::vector strVector; Appender v(strVector); tokenize(v, "A number of words to be tokenized", " \t"); 

¡Eso es! Y esa es solo una forma de usar el tokenizer, por ejemplo, cómo contar palabras:

 class WordCounter { public: WordCounter() : noOfWords(0) {} void operator() (const char*, unsigned) { ++noOfWords; } unsigned noOfWords; }; WordCounter wc; tokenize(wc, "A number of words to be counted", " \t"); ASSERT( wc.noOfWords == 7 ); 

Limitado por la imaginación;)

Aquí hay una solución simple que usa solo la biblioteca de expresiones regulares estándar

 #include  #include  #include  std::vector Tokenize( const string str, const std::regex regex ) { using namespace std; std::vector result; sregex_token_iterator it( str.begin(), str.end(), regex, -1 ); sregex_token_iterator reg_end; for ( ; it != reg_end; ++it ) { if ( !it->str().empty() ) //token could be empty:check result.emplace_back( it->str() ); } return result; } 

El argumento de expresiones regulares permite verificar múltiples argumentos (espacios, comas, etc.)

Normalmente solo controlo dividir en espacios y comas, así que también tengo esta función predeterminada:

 std::vector TokenizeDefault( const string str ) { using namespace std; regex re( "[\\s,]+" ); return Tokenize( str, re ); } 

El "[\\s,]+" busca espacios ( \\s ) y comas ( , ).

Tenga en cuenta que si quiere dividir wstring lugar de string ,

  • cambiar todo std::regex a std::wregex
  • cambia todo sregex_token_iterator a wsregex_token_iterator

Tenga en cuenta que también podría querer tomar el argumento de cadena por referencia, dependiendo de su comstackdor.

Si desea utilizar boost, pero desea utilizar una cadena completa como delimitador (en lugar de caracteres únicos como en la mayoría de las soluciones propuestas anteriormente), puede usar el boost_split_iterator .

Código de ejemplo que incluye una plantilla conveniente:

 #include  #include  #include  template inline void split( const std::string& str, const std::string& delim, _OutputIterator result) { using namespace boost::algorithm; typedef split_iterator It; for(It iter=make_split_iterator(str, first_finder(delim, is_equal())); iter!=It(); ++iter) { *(result++) = boost::copy_range(*iter); } } int main(int argc, char* argv[]) { using namespace std; vector splitted; split("HelloFOOworldFOO!", "FOO", back_inserter(splitted)); // or directly to console, for example split("HelloFOOworldFOO!", "FOO", ostream_iterator(cout, "\n")); return 0; } 

El uso de std::stringstream como funciona perfectamente funciona y hace exactamente lo que usted quería. Si solo está buscando una forma diferente de hacer las cosas, puede usar std::find() / std::find_first_of() y std::string::substr() .

Aquí hay un ejemplo:

 #include  #include  int main() { std::string s("Somewhere down the road"); std::string::size_type prev_pos = 0, pos = 0; while( (pos = s.find(' ', pos)) != std::string::npos ) { std::string substring( s.substr(prev_pos, pos-prev_pos) ); std::cout << substring << '\n'; prev_pos = ++pos; } std::string substring( s.substr(prev_pos, pos-prev_pos) ); // Last word std::cout << substring << '\n'; return 0; } 

Hay una función llamada strtok .

 #include using namespace std; vector split(char* str,const char* delim) { char* saveptr; char* token = strtok_r(str,delim,&saveptr); vector result; while(token != NULL) { result.push_back(token); token = strtok_r(NULL,delim,&saveptr); } return result; } 

Aquí hay una solución de expresiones regulares que solo usa la biblioteca de expresiones regulares estándar. (Estoy un poco oxidado, por lo que puede haber algunos errores de syntax, pero esta es al menos la idea general)

 #include  #include  #include  using namespace std; vector split(string s){ regex r ("\\w+"); //regex matches whole words, (greedy, so no fragment words) regex_iterator rit ( s.begin(), s.end(), r ); regex_iterator rend; //iterators to iterate thru words vector result(rit, rend); return result; //iterates through the matches to fill the vector } 

El stringstream puede ser conveniente si necesita analizar la cadena con símbolos que no sean espaciales:

 string s = "Name:JAck; Spouse:Susan; ..."; string dummy, name, spouse; istringstream iss(s); getline(iss, dummy, ':'); getline(iss, name, ';'); getline(iss, dummy, ':'); getline(iss, spouse, ';') 

Hasta ahora usé el de Boost , pero necesitaba algo que no depende de él, así que llegué a esto:

 static void Split(std::vector& lst, const std::string& input, const std::string& separators, bool remove_empty = true) { std::ostringstream word; for (size_t n = 0; n < input.size(); ++n) { if (std::string::npos == separators.find(input[n])) word << input[n]; else { if (!word.str().empty() || !remove_empty) lst.push_back(word.str()); word.str(""); } } if (!word.str().empty() || !remove_empty) lst.push_back(word.str()); } 

Un buen punto es que en los separators puedes pasar más de un personaje.

He rodado el mío usando strtok y usé boost para dividir una cadena. El mejor método que he encontrado es la biblioteca C ++ String Toolkit . Es increíblemente flexible y rápido.

 #include  #include  #include  #include  const char *whitespace = " \t\r\n\f"; const char *whitespace_and_punctuation = " \t\r\n\f;,="; int main() { { // normal parsing of a string into a vector of strings std::string s("Somewhere down the road"); std::vector result; if( strtk::parse( s, whitespace, result ) ) { for(size_t i = 0; i < result.size(); ++i ) std::cout << result[i] << std::endl; } } { // parsing a string into a vector of floats with other separators // besides spaces std::string s("3.0, 3.14; 4.0"); std::vector values; if( strtk::parse( s, whitespace_and_punctuation, values ) ) { for(size_t i = 0; i < values.size(); ++i ) std::cout << values[i] << std::endl; } } { // parsing a string into specific variables std::string s("angle = 45; radius = 9.9"); std::string w1, w2; float v1, v2; if( strtk::parse( s, whitespace_and_punctuation, w1, v1, w2, v2) ) { std::cout << "word " << w1 << ", value " << v1 << std::endl; std::cout << "word " << w2 << ", value " << v2 << std::endl; } } return 0; } 

El juego de herramientas tiene mucha más flexibilidad de la que muestra este sencillo ejemplo, pero es increíble su utilidad para analizar una cadena en elementos útiles.

Corto y elegante

 #include  #include  using namespace std; vector split(string data, string token) { vector output; size_t pos = string::npos; // size_t to avoid improbable overflow do { pos = data.find(token); output.push_back(data.substr(0, pos)); if (string::npos != pos) data = data.substr(pos + token.size()); } while (string::npos != pos); return output; } 

can use any string as delimiter, also can be used with binary data (std::string supports binary data, including nulls)

utilizando:

 auto a = split("this!!is!!!example!string", "!!"); 

salida:

 this is !example!string 

I made this because I needed an easy way to split strings and c-based strings… Hopefully someone else can find it useful as well. Also it doesn’t rely on tokens and you can use fields as delimiters, which is another key I needed.

I’m sure there’s improvements that can be made to even further improve its elegance and please do by all means

StringSplitter.hpp:

 #include  #include  #include  using namespace std; class StringSplit { private: void copy_fragment(char*, char*, char*); void copy_fragment(char*, char*, char); bool match_fragment(char*, char*, int); int untilnextdelim(char*, char); int untilnextdelim(char*, char*); void assimilate(char*, char); void assimilate(char*, char*); bool string_contains(char*, char*); long calc_string_size(char*); void copy_string(char*, char*); public: vector split_cstr(char); vector split_cstr(char*); vector split_string(char); vector split_string(char*); char* String; bool do_string; bool keep_empty; vector Container; vector ContainerS; StringSplit(char * in) { String = in; } StringSplit(string in) { size_t len = calc_string_size((char*)in.c_str()); String = new char[len + 1]; memset(String, 0, len + 1); copy_string(String, (char*)in.c_str()); do_string = true; } ~StringSplit() { for (int i = 0; i < Container.size(); i++) { if (Container[i] != NULL) { delete[] Container[i]; } } if (do_string) { delete[] String; } } }; 

StringSplitter.cpp:

 #include  #include  #include  #include "StringSplit.hpp" using namespace std; void StringSplit::assimilate(char*src, char delim) { int until = untilnextdelim(src, delim); if (until > 0) { char * temp = new char[until + 1]; memset(temp, 0, until + 1); copy_fragment(temp, src, delim); if (keep_empty || *temp != 0) { if (!do_string) { Container.push_back(temp); } else { string x = temp; ContainerS.push_back(x); } } else { delete[] temp; } } } void StringSplit::assimilate(char*src, char* delim) { int until = untilnextdelim(src, delim); if (until > 0) { char * temp = new char[until + 1]; memset(temp, 0, until + 1); copy_fragment(temp, src, delim); if (keep_empty || *temp != 0) { if (!do_string) { Container.push_back(temp); } else { string x = temp; ContainerS.push_back(x); } } else { delete[] temp; } } } long StringSplit::calc_string_size(char* _in) { long i = 0; while (*_in++) { i++; } return i; } bool StringSplit::string_contains(char* haystack, char* needle) { size_t len = calc_string_size(needle); size_t lenh = calc_string_size(haystack); while (lenh--) { if (match_fragment(haystack + lenh, needle, len)) { return true; } } return false; } bool StringSplit::match_fragment(char* _src, char* cmp, int len) { while (len--) { if (*(_src + len) != *(cmp + len)) { return false; } } return true; } int StringSplit::untilnextdelim(char* _in, char delim) { size_t len = calc_string_size(_in); if (*_in == delim) { _in += 1; return len - 1; } int c = 0; while (*(_in + c) != delim && c < len) { c++; } return c; } int StringSplit::untilnextdelim(char* _in, char* delim) { int s = calc_string_size(delim); int c = 1 + s; if (!string_contains(_in, delim)) { return calc_string_size(_in); } else if (match_fragment(_in, delim, s)) { _in += s; return calc_string_size(_in); } while (!match_fragment(_in + c, delim, s)) { c++; } return c; } void StringSplit::copy_fragment(char* dest, char* src, char delim) { if (*src == delim) { src++; } int c = 0; while (*(src + c) != delim && *(src + c)) { *(dest + c) = *(src + c); c++; } *(dest + c) = 0; } void StringSplit::copy_string(char* dest, char* src) { int i = 0; while (*(src + i)) { *(dest + i) = *(src + i); i++; } } void StringSplit::copy_fragment(char* dest, char* src, char* delim) { size_t len = calc_string_size(delim); size_t lens = calc_string_size(src); if (match_fragment(src, delim, len)) { src += len; lens -= len; } int c = 0; while (!match_fragment(src + c, delim, len) && (c < lens)) { *(dest + c) = *(src + c); c++; } *(dest + c) = 0; } vector StringSplit::split_cstr(char Delimiter) { int i = 0; while (*String) { if (*String != Delimiter && i == 0) { assimilate(String, Delimiter); } if (*String == Delimiter) { assimilate(String, Delimiter); } i++; String++; } String -= i; delete[] String; return Container; } vector StringSplit::split_string(char Delimiter) { do_string = true; int i = 0; while (*String) { if (*String != Delimiter && i == 0) { assimilate(String, Delimiter); } if (*String == Delimiter) { assimilate(String, Delimiter); } i++; String++; } String -= i; delete[] String; return ContainerS; } vector StringSplit::split_cstr(char* Delimiter) { int i = 0; size_t LenDelim = calc_string_size(Delimiter); while(*String) { if (!match_fragment(String, Delimiter, LenDelim) && i == 0) { assimilate(String, Delimiter); } if (match_fragment(String, Delimiter, LenDelim)) { assimilate(String,Delimiter); } i++; String++; } String -= i; delete[] String; return Container; } vector StringSplit::split_string(char* Delimiter) { do_string = true; int i = 0; size_t LenDelim = calc_string_size(Delimiter); while (*String) { if (!match_fragment(String, Delimiter, LenDelim) && i == 0) { assimilate(String, Delimiter); } if (match_fragment(String, Delimiter, LenDelim)) { assimilate(String, Delimiter); } i++; String++; } String -= i; delete[] String; return ContainerS; } 

Ejemplos:

 int main(int argc, char*argv[]) { StringSplit ss = "This:CUT:is:CUT:an:CUT:example:CUT:cstring"; vector Split = ss.split_cstr(":CUT:"); for (int i = 0; i < Split.size(); i++) { cout << Split[i] << endl; } return 0; } 

Will output:

Esta
es
un
ejemplo
cstring

 int main(int argc, char*argv[]) { StringSplit ss = "This:is:an:example:cstring"; vector Split = ss.split_cstr(':'); for (int i = 0; i < Split.size(); i++) { cout << Split[i] << endl; } return 0; } int main(int argc, char*argv[]) { string mystring = "This[SPLIT]is[SPLIT]an[SPLIT]example[SPLIT]string"; StringSplit ss = mystring; vector Split = ss.split_string("[SPLIT]"); for (int i = 0; i < Split.size(); i++) { cout << Split[i] << endl; } return 0; } int main(int argc, char*argv[]) { string mystring = "This|is|an|example|string"; StringSplit ss = mystring; vector Split = ss.split_string('|'); for (int i = 0; i < Split.size(); i++) { cout << Split[i] << endl; } return 0; } 

To keep empty entries (by default empties will be excluded):

 StringSplit ss = mystring; ss.keep_empty = true; vector Split = ss.split_string(":DELIM:"); 

The goal was to make it similar to C#'s Split() method where splitting a string is as easy as:

 String[] Split = "Hey:cut:what's:cut:your:cut:name?".Split(new[]{":cut:"}, StringSplitOptions.None); foreach(String X in Split) { Console.Write(X); } 

I hope someone else can find this as useful as I do.

¿Qué tal esto?

 #include  #include  using namespace std; vector split(string str, const char delim) { vector v; string tmp; for(string::const_iterator i; i = str.begin(); i <= str.end(); ++i) { if(*i != delim && i != str.end()) { tmp += *i; } else { v.push_back(tmp); tmp = ""; } } return v; } 

Here’s another way of doing it..

 void split_string(string text,vector& words) { int i=0; char ch; string word; while(ch=text[i++]) { if (isspace(ch)) { if (!word.empty()) { words.push_back(word); } word = ""; } else { word += ch; } } if (!word.empty()) { words.push_back(word); } } 

I like to use the boost/regex methods for this task since they provide maximum flexibility for specifying the splitting criteria.

 #include  #include  #include  int main() { std::string line("A:::line::to:split"); const boost::regex re(":+"); // one or more colons // -1 means find inverse matches aka split boost::sregex_token_iterator tokens(line.begin(),line.end(),re,-1); boost::sregex_token_iterator end; for (; tokens != end; ++tokens) std::cout << *tokens << std::endl; } 

Recently I had to split a camel-cased word into subwords. There are no delimiters, just upper characters.

 #include  #include  #include  // std::isupper template const std::list split_camel_case_string(const String &s) { std::list R; String w; for (String::const_iterator i = s.begin(); i < s.end(); ++i) { { if (std::isupper(*i)) { if (w.length()) { R.push_back(w); w.clear(); } } w += *i; } if (w.length()) R.push_back(w); return R; } 

For example, this splits "AQueryTrades" into "A", "Query" and "Trades". The function works with narrow and wide strings. Because it respects the current locale it splits "RaumfahrtÜberwachungsVerordnung" into "Raumfahrt", "Überwachungs" and "Verordnung".

Note std::upper should be really passed as function template argument. Then the more generalized from of this function can split at delimiters like "," , ";" or " " too.

Get Boost ! : -)

 #include  #include  #include  #include  using namespace std; using namespace boost; int main(int argc, char**argv) { typedef vector < string > list_type; list_type list; string line; line = "Somewhere down the road"; split(list, line, is_any_of(" ")); for(int i = 0; i < list.size(); i++) { cout << list[i] << endl; } return 0; } 

This example gives the output -

 Somewhere down the road 

The code below uses strtok() to split a string into tokens and stores the tokens in a vector.

 #include  #include  #include  #include  using namespace std; char one_line_string[] = "hello hi how are you nice weather we are having ok then bye"; char seps[] = " ,\t\n"; char *token; int main() { vector vec_String_Lines; token = strtok( one_line_string, seps ); cout << "Extracting and storing data in a vector..\n\n\n"; while( token != NULL ) { vec_String_Lines.push_back(token); token = strtok( NULL, seps ); } cout << "Displaying end result in vector line storage..\n\n"; for ( int i = 0; i < vec_String_Lines.size(); ++i) cout << vec_String_Lines[i] << "\n"; cout << "\n\n\n"; return 0; } 
 #include #include #include #include using namespace std; vector split(const string &s, char delim) { vector elems; stringstream ss(s); string item; while (getline(ss, item, delim)) { elems.push_back(item); } return elems; } int main() { vector x = split("thi is an sample test",' '); unsigned int i; for(i=0;i