2009-03-01 35 views
19

¿está bien? por la cadena me refiero a std :: string¿Existe una forma integrada de dividir cadenas en C++?

+5

http://stackoverflow.com/questions/236129/c-how-to-split-a-string – sykora

+3

Por mucho que me encanta C++, todavía odio deformar mi mente en torno a sus hilos. – pyon

+0

ah bien. parece una pregunta duplicada Recomiendo cerrar este y luego redireccionar a las personas al otro "c-how-to-split-a-string".¿qué piensas? –

Respuesta

-2

cadenas de C

Basta con insertar una \0 donde desea dividir. Esto es lo más integrado que se puede obtener con las funciones C estándar.

Esta función se divide en la primera aparición de un separador char, devolviendo la segunda cadena.

char *split_string(char *str, char separator) { 
    char *second = strchr(str, separator); 
    if(second == NULL) 
     return NULL; 

    *second = '\0'; 
    ++second; 
    return second; 
} 
+0

¿por qué no usar strtok()? – cdonner

+0

@cdonner, porque strchr es más simple. =] – strager

+1

@strager: Esto es un mal diseño: modifica la entrada. Aunque esto es algo que strtok() ha estado haciendo y se ha salido con la suya. – dirkgently

1

La respuesta es no. Tienes que dividirlos usando una de las funciones de la biblioteca.

algo que utilizo:

std::vector<std::string> parse(std::string l, char delim) 
{ 
    std::replace(l.begin(), l.end(), delim, ' '); 
    std::istringstream stm(l); 
    std::vector<std::string> tokens; 
    for (;;) { 
     std::string word; 
     if (!(stm >> word)) break; 
     tokens.push_back(word); 
    } 
    return tokens; 
} 

También puede echar un vistazo al método basic_streambuf<T>::underflow() y escribir un filtro.

+0

he editado para especificar, i std std :: string –

7

cadenas STL

Puede usar iteradores de cadena para hacer su trabajo sucio.

std::string str = "hello world"; 

std::string::const_iterator pos = std::find(string.begin(), string.end(), ' '); // Split at ' '. 

std::string left(str.begin(), pos); 
std::string right(pos + 1, str.end()); 

// Echoes "hello|world". 
std::cout << left << "|" << right << std::endl; 
+0

¿Sería esto aplicable solo para una cadena de dos palabras? –

3
void split(string StringToSplit, string Separators) 
{ 
    size_t EndPart1 = StringToSplit.find_first_of(Separators) 
    string Part1 = StringToSplit.substr(0, EndPart1); 
    string Part2 = StringToSplit.substr(EndPart1 + 1); 
} 
+0

gracias, si esto termina en algún programa de código abierto en alguna parte, tendré que darle crédito :) –

11

No hay manera integrada para dividir una cadena en C++, pero boost proporciona la biblioteca string algo para hacer todo tipo de manipulación de cadenas, incluyendo cadena splitting.

18

Aquí hay una función de división de estilo Perl que utilizo:

void split(const string& str, const string& delimiters , vector<string>& tokens) 
{ 
    // 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); 
    } 
} 
+0

Me gusta esta solución. A diferencia de la mayoría de las otras soluciones, no requiere refuerzo, combina delimitadores, admite múltiples delimitadores, está bien documentado y es bastante compacto y fácil de entender para noobs como yo. Solo cambiaría el parámetro delimeters para tomar un valor predeterminado, como en el original: http://oopweb.com/CPP/Documents/CPPHOWTO/Volume/C++Programming-HOWTO-7.html :-) – JJC

+0

Además, los noobs como yo deberían tener cuidado de borrar el vector cada vez que llaman a esta función si esperan que solo contenga el último conjunto de tokens. (use tokens.clear()). – JJC

+1

Subproceso antiguo que apareció en una búsqueda. Cambiaría la firma de 'split' para no tener un tercer parámetro, y devolvería el' vector 'en su lugar (' tokens' será una variable local). –

0

¿Qué diablos ... Aquí está mi versión ...

Nota: que parte en ("XZaaaXZ", "XZ") te dará 3 cuerdas 2 de esas cadenas estarán vacías, y no se agregará a en el StringVector si el IncludeEmptyStrings es falso.

Delimitador es no cualquier elemento en el conjunto, sino que coincide con esa cadena exacta.

inline void 
StringSplit(vector<string> * theStringVector, /* Altered/returned value */ 
      const string & theString, 
      const string & theDelimiter, 
      bool    theIncludeEmptyStrings = false) 
{ 
    UASSERT(theStringVector, !=, (vector<string> *) NULL); 
    UASSERT(theDelimiter.size(), >, 0); 

    size_t start = 0, end = 0, length = 0; 

    while (end != string::npos) 
    { 
    end = theString.find(theDelimiter, start); 

     // If at end, use length=maxLength. Else use length=end-start. 
    length = (end == string::npos) ? string::npos : end - start; 

    if ( theIncludeEmptyStrings 
     || ( (length > 0) /* At end, end == length == string::npos */ 
      && (start < theString.size()))) 
     theStringVector -> push_back(theString.substr(start, length)); 

     // If at end, use start=maxSize. Else use start=end+delimiter. 
    start = ( (end > (string::npos - theDelimiter.size())) 
       ? string::npos : end + theDelimiter.size() ); 
    } 
} 


inline vector<string> 
StringSplit(const string & theString, 
      const string & theDelimiter, 
      bool    theIncludeEmptyStrings = false) 
{ 
    vector<string> v; 
    StringSplit(& v, theString, theDelimiter, theIncludeEmptyStrings); 
    return v; 
} 
-2

Un método bastante sencillo sería utilizar el método c_str() de std :: string para obtener una matriz de caracteres de estilo C, a continuación, utilizar strtok() para tokenize la cadena. No es tan elocuente como algunas de las otras soluciones enumeradas aquí, pero es fácil y funciona.

+2

strtok escribe en la memoria apuntada a. c_str() apunta a la memoria en la que no debe escribirse (invariante de la clase de cadena - podría romper silenciosamente cosas como la semántica de copiar y escribir). el estándar de C++ lo prohíbe. Puedes copiar primero a std :: vector, luego puedes usar strtok. –

+0

El método c_str devuelve una cadena const que apunta a la representación interna. Es const así que también tendrías que strdup o copiarlo a un vector. Se me pidió una forma C++ así que estoy bajando esto. – Matt

10

Yup, stringstream.

std::istringstream oss(std::string("This is a test string")); 
std::string word; 
while(oss >> word) { 
    std::cout << "[" << word << "] "; 
} 
+0

Debe ser istringstream. – cpx

+0

@ Dave18: gracias – MSalters

+3

Este es mi divisor de caballo de trabajo. Si desea dividir en un delimitador, puede simplemente reemplazar 'oss >> word' con' getline (oss, word, ':') ' – Eponymous

0

No hay una forma común de hacerlo.

Prefiero el boost::tokenizer, solo su encabezado y fácil de usar.

Cuestiones relacionadas