2009-05-21 6 views
4

Je joue avec la bibliothèque de chaînes boost et je viens de rencontrer la simplicité impressionnante de la méthode split.Utilisation de escaped_list_separator avec split boost

string delimiters = ","; 
    string str = "string, with, comma, delimited, tokens, \"and delimiters, inside a quote\""; 
    // If we didn't care about delimiter characters within a quoted section we could us 
    vector<string> tokens; 
    boost::split(tokens, str, boost::is_any_of(delimiters)); 
    // gives the wrong result: tokens = {"string", " with", " comma", " delimited", " tokens", "\"and delimiters", " inside a quote\""} 

Ce qui serait bien et concis ... mais il ne semble pas travailler avec des citations et au lieu que je dois faire quelque chose comme

string delimiters = ","; 
string str = "string, with, comma, delimited, tokens, \"and delimiters, inside a quote\""; 
vector<string> tokens; 
escaped_list_separator<char> separator("\\",delimiters, "\""); 
typedef tokenizer<escaped_list_separator<char> > Tokeniser; 
Tokeniser t(str, separator); 
for (Tokeniser::iterator it = t.begin(); it != t.end(); ++it) 
    tokens.push_back(*it); 
// gives the correct result: tokens = {"string", " with", " comma", " delimited", " tokens", "\"and delimiters, inside a quote\""} 

suivant Ma question est peut diviser ou d'une autre algorithme standard être utilisé lorsque vous avez cité des délimiteurs? Merci à Purpledog mais j'ai déjà un moyen non-obsolète d'atteindre le résultat souhaité, je pense juste que c'est assez lourd et à moins que je puisse le remplacer par une solution plus simple et élégante je ne l'utiliserais pas en général sans l'envelopper encore une autre méthode.

EDIT: Code mis à jour pour afficher les résultats et clarifier la question.

Répondre

5

Il ne semble pas qu'il y ait une façon simple de le faire en utilisant la méthode boost :: Split. Le plus court morceau de code que je peux trouver pour ce faire est

vector<string> tokens; 
tokenizer<escaped_list_separator<char> > t(str, escaped_list_separator<char>("\\", ",", "\"")); 
BOOST_FOREACH(string s, escTokeniser) 
    tokens.push_back(s); 

qui est à peine plus prolixe que l'extrait d'origine

vector<string> tokens; 
boost::split(tokens, str, boost::is_any_of(",")); 
2

Je ne connais pas la bibliothèque boost :: string mais en utilisant le boost regex_token_iterator vous pourrez exprimer des délimiteurs en termes d'expression régulière. Alors oui, vous pouvez utiliser des délimiteurs entre guillemets, et des choses beaucoup plus complexes aussi. Notez que cela était fait avec regex_split qui est maintenant obsolète.

Voici un exemple tiré de l'élan doc:

#include <iostream> 
#include <boost/regex.hpp> 

using namespace std; 

int main(int argc) 
{ 
    string s; 
    do{ 
     if(argc == 1) 
     { 
     cout << "Enter text to split (or \"quit\" to exit): "; 
     getline(cin, s); 
     if(s == "quit") break; 
     } 
     else 
     s = "This is a string of tokens"; 

     boost::regex re("\\s+"); 
     boost::sregex_token_iterator i(s.begin(), s.end(), re, -1); 
     boost::sregex_token_iterator j; 

     unsigned count = 0; 
     while(i != j) 
     { 
     cout << *i++ << endl; 
     count++; 
     } 
     cout << "There were " << count << " tokens found." << endl; 

    }while(argc == 1); 
    return 0; 
} 

Si le programme est démarré avec Bonjour tout le monde comme argument la sortie est:

hello 
world 
There were 2 tokens found. 

Changer boost :: regex re ("\ s +"); en boost :: regex re ("\", \ ""); diviserait les délimiteurs entre guillemets. démarrer le programme avec bonjour « » monde comme argument entraînerait également:

hello 
world 
There were 2 tokens found. 

Mais je suppose que vous voulez traiter des choses comme ça: « monde » « bonjour », dans ce cas, une solution est:

  1. split avec coma ne
  2. supprimer alors le "" (éventuellement en utilisant boost/algorithme/string/trim.hpp ou la bibliothèque regex).

EDIT: Sortie de programme ajouté

+0

L'exemple que vous avez donné serait amélioré si vous montriez la sortie aussi. Juste pour le rendre très clair à tous ceux qui trouvent cette page ce que fait le code. –

2

Cela permettra d'atteindre le même résultat que la réponse de Jamie Cook, sans la boucle explicite .

tokenizer<escaped_list_separator<char> >tok(str); 
vector<string> tokens(tok.begin(), tok.end()); 

Le deuxième paramètre par défaut du constructeur tokenizer à escaped_list_separator<char>("\\", ",", "\"") il est donc pas nécessaire. Sauf si vous avez des exigences différentes pour les virgules ou les citations.

Questions connexes