Analizar (dividir) una cadena en C ++ usando un delimitador de cadena (C ++ estándar)

Estoy analizando una cadena en C ++ usando lo siguiente:

string parsed,input="text to be parsed"; stringstream input_stringstream(input); if(getline(input_stringstream,parsed,' ')) { // do some processing. } 

El análisis con un único delimitador de caracteres está bien. Pero, ¿y si quiero usar una cadena como delimitador?

Ejemplo: quiero dividir:

 scott>=tiger 

con> = como delimitador para poder obtener scott y tigre.

Puede usar la función std::string::find() para encontrar la posición de su delimitador de cadena, luego use std::string::substr() para obtener un token.

Ejemplo:

 std::string s = "scott>=tiger"; std::string delimiter = ">="; std::string token = s.substr(0, s.find(delimiter)); // token is "scott" 
  • La función find(const string& str, size_t pos = 0) devuelve la posición de la primera aparición de str en la cadena, o npos si la cadena no se encuentra.

  • La función substr(size_t pos = 0, size_t n = npos) devuelve una subcadena del objeto, comenzando en la posición pos y de la longitud npos .


Si tiene múltiples delimitadores, después de haber extraído un token, puede eliminarlo (delimitador incluido) para proceder con las extracciones posteriores (si desea conservar el hilo original, simplemente use s = s.substr(pos + delimiter.length()); ):

 s.erase(0, s.find(delimiter) + delimiter.length()); 

De esta forma, puede hacer bucles fácilmente para obtener cada token.

Ejemplo completo

 std::string s = "scott>=tiger>=mushroom"; std::string delimiter = ">="; size_t pos = 0; std::string token; while ((pos = s.find(delimiter)) != std::string::npos) { token = s.substr(0, pos); std::cout < < token << std::endl; s.erase(0, pos + delimiter.length()); } std::cout << s << std::endl; 

Salida:

 scott tiger mushroom 

Este método usa std::string::find sin mutar la cadena original al recordar el principio y el final del token de subserie anterior.

 #include  #include  int main() { std::string s = "scott>=tiger"; std::string delim = ">="; auto start = 0U; auto end = s.find(delim); while (end != std::string::npos) { std::cout < < s.substr(start, end - start) << std::endl; start = end + delim.length(); end = s.find(delim, start); } std::cout << s.substr(start, end); } 

Puede usar la siguiente función para dividir una cadena:

 vector split(const string& str, const string& delim) { vector tokens; size_t prev = 0, pos = 0; do { pos = str.find(delim, prev); if (pos == string::npos) pos = str.length(); string token = str.substr(prev, pos-prev); if (!token.empty()) tokens.push_back(token); prev = pos + delim.length(); } while (pos < str.length() && prev < str.length()); return tokens; } 

strtok le permite pasar múltiples caracteres como delimitadores. Apuesto a que si pasó en “> =” su cadena de ejemplo se dividiría correctamente (incluso si el> y = se cuentan como delimitadores individuales).

EDITAR si no quiere usar c_str() para convertir de cadena a char *, puede usar substr y find_first_of para tokenize.

 string token, mystring("scott>=tiger"); while(token != mystring){ token = mystring.substr(0,mystring.find_first_of(">=")); mystring = mystring.substr(mystring.find_first_of(">=") + 1); printf("%s ",token.c_str()); } 

Este código divide las líneas del texto y agrega a todos a un vector.

 vector split(char *phrase, string delimiter){ vector list; string s = string(phrase); size_t pos = 0; string token; while ((pos = s.find(delimiter)) != string::npos) { token = s.substr(0, pos); list.push_back(token); s.erase(0, pos + delimiter.length()); } return list; } 

Llamado por:

 vector listFilesMax = split(buffer, "\n"); 

Yo usaría boost::tokenizer . Aquí hay documentación que explica cómo hacer una función de tokenizador apropiada: http://www.boost.org/doc/libs/1_52_0/libs/tokenizer/tokenizerfunction.htm

Aquí hay uno que funciona para su caso.

 struct my_tokenizer_func { template bool operator()(It& next, It end, std::string & tok) { if (next == end) return false; char const * del = ">="; auto pos = std::search(next, end, del, del + 2); tok.assign(next, pos); next = pos; if (next != end) std::advance(next, 2); return true; } void reset() {} }; int main() { std::string to_be_parsed = "1) one>=2) two>=3) three>=4) four"; for (auto i : boost::tokenizer(to_be_parsed)) std::cout < < i << '\n'; } 

Aquí está mi opinión sobre esto. Maneja los casos extremos y toma un parámetro opcional para eliminar las entradas vacías de los resultados.

 bool endsWith(const std::string& s, const std::string& suffix) { return s.size() >= suffix.size() && s.substr(s.size() - suffix.size()) == suffix; } std::vector split(const std::string& s, const std::string& delimiter, const bool& removeEmptyEntries = false) { std::vector tokens; for (size_t start = 0, end; start < s.length(); start = end + delimiter.length()) { size_t position = s.find(delimiter, start); end = position != string::npos ? position : s.length(); std::string token = s.substr(start, end - start); if (!removeEmptyEntries || !token.empty()) { tokens.push_back(token); } } if (!removeEmptyEntries && (s.empty() || endsWith(s, delimiter))) { tokens.push_back(""); } return tokens; } 

Ejemplos

 split("abc", "-"); // [3]("a","b","c") split("a--c", "-"); // [3]("a","","c") split("-b-", "-"); // [3]("","b","") split("--c--", "-"); // [5]("","","c","","") split("--c--", "-", true); // [1]("c") split("a", "-"); // [1]("a") split("", "-"); // [1]("") split("", "-", true); // [0]() 

Para delimitador de cadenas
División de cadena basada en cadena de delimitador. Como la división de la cadena "adsf-+qwret-+nvfkbdsj-+orthdfjgh-+dfjrleih" basada en la cadena delimitadora "-+" , la salida será {"adsf", "qwret", "nvfkbdsj", "orthdfjgh", "dfjrleih"}

 #include  #include  #include  using namespace std; // for string delimiter vector split(string s, string delimiter) { size_t pos_start = 0, pos_end, delim_len = delimiter.length(); string token; vector res; while ((pos_end = s.find(delimiter, pos_start)) != string::npos) { token = s.substr(pos_start, pos_end - pos_start); pos_start = pos_end + delim_len; res.push_back(token); } res.push_back(s.substr(pos_start)); return res; } int main() { string str = "adsf-+qwret-+nvfkbdsj-+orthdfjgh-+dfjrleih"; string delimiter = "-+"; vector v = split(str, delimiter); for (auto i : v) cout < < i << endl; return 0; } 

Para el delimitador de caracteres individuales

 #include  #include  #include  using namespace std; vector split(const string &s, char delim) { vector result; stringstream ss(s); string item; while (getline(ss, item, delim)) { result.push_back(item); } return result; } int main() { string str = "adsf+qwer+poui+fdgh"; vector v = split(str, '+'); for (auto i : v) cout < < i << endl; return 0; } 

Si no desea modificar la cadena (como en la respuesta de Vincenzo Pii) y desea generar el último token también, puede utilizar este enfoque:

 inline std::vector splitString( const std::string &s, const std::string &delimiter ){ std::vector ret; size_t start = 0; size_t end = 0; size_t len = 0; std::string token; do{ end = s.find(delimiter,start); len = end - start; token = s.substr(start, len); ret.emplace_back( token ); start += len + delimiter.length(); std::cout < < token << std::endl; }while ( end != std::string::npos ); return ret; } 
 #include #include using namespace std; int split_count(string str,char delimit){ return count(str.begin(),str.end(),delimit); } void split(string str,char delimit,string res[]){ int a=0,i=0; while(a 

PD: Funciona solo si las longitudes de las cuerdas después de la división son iguales

 std::vector split(const std::string& s, char c) { std::vector v; unsigned int ii = 0; unsigned int j = s.find(c); while (j < s.length()) { v.push_back(s.substr(i, j - i)); i = ++j; j = s.find(c, j); if (j >= s.length()) { v.push_back(s.substr(i, s,length())); break; } } return v; }