2011-05-04 62 views
27

posible duplicado:
How to split a string in C++?Separar una cadena por espacios

tengo que dividir una cadena de espacios individuales y almacenarlo en una matriz de cadenas. Puedo lograr esto usando un istringstream, pero lo que no puedo lograr es esto:

Quiero que cada espacio termine la palabra actual. Entonces, si hay dos espacios consecutivos, un elemento de mi matriz debe estar en blanco.

Por ejemplo:

(subrayado denota el espacio)

This_is_a_string. 
gets split into: 
A[0] = This 
A[1] = is 
A[2] = a 
A[3] = string. 

This__is_a_string. 
gets split into: 
A[0] = This 
A[1] = "" 
A[2] = is 
A[3] = a 
A[4] = string. 

¿Cómo puedo aplicar esto?

Respuesta

20

Incluso puede desarrollar su propia función de división (lo sé, poco pasada de moda):

unsigned int split(const std::string &txt, std::vector<std::string> &strs, char ch) 
{ 
    unsigned int pos = txt.find(ch); 
    unsigned int initialPos = 0; 
    strs.clear(); 

    // Decompose statement 
    while(pos != std::string::npos) { 
     strs.push_back(txt.substr(initialPos, pos - initialPos + 1)); 
     initialPos = pos + 1; 

     pos = txt.find(ch, initialPos); 
    } 

    // Add the last one 
    strs.push_back(txt.substr(initialPos, std::min(pos, txt.size()) - initialPos + 1)); 

    return strs.size(); 
} 

Entonces sólo tiene que invocar con un vector <cadena> como argumento:

int main() 
{ 
    std::vector<std::string> v; 

    split("This is a test", v, ' '); 
    show(v); 

    return 0; 
} 
+0

¡Advertencia! :) Si desea tener elementos sin espacios, reemplace ambas ocurrencias de "- initialPos + 1" por solo "- initialPos" – teejay

2

Si no es reacio a impulsar, boost.tokenizer es lo suficientemente flexible para resolver este

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

void split_and_show(const std::string s) 
{ 
    boost::char_separator<char> sep(" ", "", boost::keep_empty_tokens); 
    boost::tokenizer<boost::char_separator<char> > tok(s, sep); 
    for(auto i = tok.begin(); i!=tok.end(); ++i) 
      std::cout << '"' << *i << "\"\n"; 
} 
int main() 
{ 
    split_and_show("This is a string"); 
    split_and_show("This is a string"); 

} 

prueba: https://ideone.com/mN2sR

4

Se puede utilizar boost?

samm$ cat split.cc 
#include <boost/algorithm/string/classification.hpp> 
#include <boost/algorithm/string/split.hpp> 

#include <boost/foreach.hpp> 

#include <iostream> 
#include <string> 
#include <vector> 

int 
main() 
{ 
    std::string split_me("hello world how are you"); 

    typedef std::vector<std::string> Tokens; 
    Tokens tokens; 
    boost::split(tokens, split_me, boost::is_any_of(" ")); 

    std::cout << tokens.size() << " tokens" << std::endl; 
    BOOST_FOREACH(const std::string& i, tokens) { 
     std::cout << "'" << i << "'" << std::endl; 
    } 
} 

ejecución de la muestra:

samm$ ./a.out 
8 tokens 
'hello' 
'world' 
'' 
'how' 
'are' 
'' 
'' 
'you' 
samm$ 
+0

este tiene una mejor legibilidad –

3

Si usted es reacio a aumentar, se puede usar regularmente edad operator>>, junto con std::noskipws:

EDIT: cambios después de la prueba.

#include <iostream> 
#include <iomanip> 
#include <vector> 
#include <string> 
#include <algorithm> 
#include <iterator> 
#include <sstream> 

void split(const std::string& str, std::vector<std::string>& v) { 
    std::stringstream ss(str); 
    ss >> std::noskipws; 
    std::string field; 
    char ws_delim; 
    while(1) { 
    if(ss >> field) 
     v.push_back(field); 
    else if (ss.eof()) 
     break; 
    else 
     v.push_back(std::string()); 
    ss.clear(); 
    ss >> ws_delim; 
    } 
} 

int main() { 
    std::vector<std::string> v; 
    split("hello world how are you", v); 
    std::copy(v.begin(), v.end(), std::ostream_iterator<std::string>(std::cout, "-")); 
    std::cout << "\n"; 
} 

http://ideone.com/62McC

0

Se podía utilizado simple función strtok() (*) From here. Tenga en cuenta que las fichas se crean en delimitadores

#include <stdio.h> 
#include <string.h> 

int main() 
{ 
    char str[] ="- This is a string"; 
    char * pch; 
    printf ("Splitting string \"%s\" into tokens:\n",str); 
    pch = strtok (str," ,.-"); 
    while (pch != NULL) 
    { 
    printf ("%s\n",pch); 
    pch = strtok (NULL, " ,.-"); 
    } 
    return 0; 
} 
1

También puede simplemente utilizar el chapado a la antigua 'strtok'

http://www.cplusplus.com/reference/clibrary/cstring/strtok/

Es un poco flojo pero no implica el uso de impulso (no es que es impulso una cosa mala).

Básicamente, llama a strtok con la cadena que quieras dividir y el delimitador (en este caso un espacio) y te devolverá un char *.

Desde el enlace:

#include <stdio.h> 
#include <string.h> 

int main() 
{ 
    char str[] ="- This, a sample string."; 
    char * pch; 
    printf ("Splitting string \"%s\" into tokens:\n",str); 
    pch = strtok (str," ,.-"); 
    while (pch != NULL) 
    { 
    printf ("%s\n",pch); 
    pch = strtok (NULL, " ,.-"); 
    } 
    return 0; 
} 
19

Si estrictamente un carácter de espacio es el delimitador, probablemente std::getline será válida.
Por ejemplo:

int main() { 
    using namespace std; 
    istringstream iss("This is a string"); 
    string s; 
    while (getline(iss, s, ' ')) { 
    printf("`%s'\n", s.c_str()); 
    } 
} 
+2

puede alguien explicar la sobrecarga de rendimiento de 'línea de cuerda, palabra; while (getline (cin, línea)) { istringstream ss (línea); while (ss >> word) // palabra parse } ' Para ser específico, ¿cómo se implementa el constructor istringstream de la cadena? ¿Copia la cadena? ¿El compilador será lo suficientemente inteligente como para mover la declaración ss fuera del ciclo while? Gracias – csyangchen

+0

implementación bastante simple. ¡Gracias! –

Cuestiones relacionadas