Je ne peux pas croire que cette tâche de routine soit un tel casse-tête en C ++
wfbarksdale
6
Ce n'est pas un casse-tête en c ++ - il existe différentes façons d'y parvenir. les programmeurs sont moins conscients du c ++ que du c # - c'est sur le marketing et les investissements ... voyez ceci pour diverses options c ++ pour obtenir le même: cplusplus.com/faq/sequences/strings/split
hB0
9
@ hB0 passe par beaucoup de réponses aux questions et ne décide toujours pas des moyens est un casse-tête. l'un a besoin de cette bibliothèque, l'autre est juste pour les espaces, l'autre ne gère pas les espaces ..
Les algorithmes de bibliothèque standard C ++ sont assez universellement basés autour d'itérateurs plutôt que de conteneurs concrets. Malheureusement, cela rend difficile la fourniture d'une splitfonction de type Java dans la bibliothèque standard C ++, même si personne ne prétend que ce serait pratique. Mais quel serait son type de retour?std::vector<std::basic_string<…>>? Peut-être, mais alors nous sommes obligés d'effectuer des allocations (potentiellement redondantes et coûteuses).
Au lieu de cela, C ++ offre une multitude de façons de diviser les chaînes en fonction de délimiteurs arbitrairement complexes, mais aucune d'entre elles n'est aussi bien encapsulée que dans d'autres langages. Les nombreuses façons de remplir des articles de blog entiers .
À sa plus simple expression, vous pouvez répéter l’utilisation std::string::findjusqu’à ce que vous frappiez std::string::nposet extraire le contenu à l’aide destd::string::substr .
Une version plus fluide (et idiomatique, mais basique) pour le fractionnement sur un espace blanc utiliserait std::istringstream:
auto iss = std::istringstream{"The quick brown fox"};auto str = std::string{};while(iss >> str){
process(str);}
À l'aide de std::istream_iterators , le contenu du flux de chaînes peut également être copié dans un vecteur à l'aide de son constructeur de plage d'itérateur.
Plusieurs bibliothèques (telles que Boost.Tokenizer ) proposent des tokenisers spécifiques.
Un fractionnement plus avancé nécessite des expressions régulières. C ++ fournit notamment std::regex_token_iteratorà cet effet:
autoconst str ="The quick brown fox"s;autoconst re = std::regex{R"(\s+)"};autoconst vec = std::vector<std::string>(
std::sregex_token_iterator{begin(str), end(str), re,-1},
std::sregex_token_iterator{});
Malheureusement, le boost n'est pas toujours disponible pour tous les projets. Je vais devoir chercher une réponse non boost.
FuzzyBunnySlippers
36
Tous les projets ne sont pas ouverts à "l'open source". Je travaille dans des secteurs fortement réglementés. Ce n'est pas vraiment un problème. C'est juste une réalité de la vie. Boost n'est pas disponible partout.
FuzzyBunnySlippers
5
@NonlinearIdeas L'autre question / réponse ne concernait pas du tout les projets Open Source. Il en va de même pour tout projet. Cela dit, je comprends bien sûr les normes restreintes telles que MISRA C, mais il est entendu que vous construisez tout à partir de zéro (à moins que vous ne trouviez une bibliothèque conforme - une rareté). Quoi qu'il en soit, le fait n'est pas que «Boost n'est pas disponible» - c'est que vous avez des exigences spéciales pour lesquelles presque toutes les réponses à usage général seraient inappropriées.
Konrad Rudolph
1
@NonlinearIdeas Exemple, les autres réponses non-Boost ne sont pas non plus conformes à MISRA.
Konrad Rudolph
3
@Dmitry Qu'est-ce que "STL barf"?! Et toute la communauté est très favorable au remplacement du préprocesseur C - en fait, il y a des propositions pour le faire. Mais votre suggestion d'utiliser PHP ou un autre langage à la place serait un énorme pas en arrière.
Konrad Rudolph
188
le classe de tokenizer Boost peut rendre ce genre de chose assez simple:
#include<iostream>#include<string>#include<boost/foreach.hpp>#include<boost/tokenizer.hpp>usingnamespace std;usingnamespace boost;int main(int,char**){
string text ="token, test string";
char_separator<char> sep(", ");
tokenizer< char_separator<char>> tokens(text, sep);
BOOST_FOREACH (const string& t, tokens){
cout << t <<"."<< endl;}}
Mis à jour pour C ++ 11:
#include<iostream>#include<string>#include<boost/tokenizer.hpp>usingnamespace std;usingnamespace boost;int main(int,char**){
string text ="token, test string";
char_separator<char> sep(", ");
tokenizer<char_separator<char>> tokens(text, sep);for(constauto& t : tokens){
cout << t <<"."<< endl;}}
Bon, j'ai récemment utilisé ça. Mon compilateur Visual Studio a un étrange bourdonnement jusqu'à ce que j'utilise un espace pour séparer les deux caractères ">" avant les jetons (texte, sep): (erreur C2947: attendre que '>' termine le modèle-liste d'arguments, trouvé '> > ')
AndyUK
@AndyUK oui, sans l'espace, le compilateur le traite comme un opérateur d'extraction plutôt que comme deux modèles de fermeture.
EnabrenTane
Théoriquement, cela a été corrigé en C ++ 0x
David Souther
3
méfiez-vous des troisièmes paramètres du char_separatorconstructeur ( drop_empty_tokensc'est la valeur par défaut, l'alternative l'est keep_empty_tokens).
Benoit
5
@puk - C'est un suffixe couramment utilisé pour les fichiers d'en-tête C ++. (comme .hpour les en-têtes C)
Ferruccio
167
En voici une très simple:
#include<vector>#include<string>usingnamespace std;vector<string> split(constchar*str,char c =' '){vector<string> result;do{constchar*begin = str;while(*str != c &&*str)
str++;
result.push_back(string(begin, str));}while(0!=*str++);return result;}
dois-je ajouter un prototype pour cette méthode dans le fichier .h?
Suhrob Samiev
5
Ce n'est pas exactement la «meilleure» réponse car elle utilise toujours un littéral de chaîne qui est le tableau de caractères constants en C simple. Je crois que le questionneur demandait s'il pouvait symboliser une chaîne C ++ qui est de type "chaîne" introduite par ce dernier.
Vijay Kumar Kanta
Cela nécessite une nouvelle réponse car je soupçonne fortement que l'inclusion d'expressions régulières dans C ++ 11 a changé la meilleure réponse.
Omnifarious
114
Utilisez strtok. À mon avis, il n'est pas nécessaire de créer une classe autour de la tokenisation à moins que strtok ne vous fournisse pas ce dont vous avez besoin. Ce n'est peut-être pas le cas, mais en 15 ans et plus d'écriture de divers codes d'analyse en C et C ++, j'ai toujours utilisé strtok. Voici un exemple
char myString[]="The quick brown fox";char*p = strtok(myString," ");while(p){
printf ("Token: %s\n", p);
p = strtok(NULL," ");}
Quelques mises en garde (qui pourraient ne pas convenir à vos besoins). La chaîne est "détruite" au cours du processus, ce qui signifie que les caractères EOS sont placés en ligne dans les points de délimitation. Une utilisation correcte peut vous obliger à créer une version non constante de la chaîne. Vous pouvez également modifier la liste des délimiteurs en cours d'analyse.
À mon avis, le code ci-dessus est beaucoup plus simple et plus facile à utiliser que d'écrire une classe distincte pour lui. Pour moi, c'est l'une de ces fonctions que le langage fournit et il le fait bien et proprement. C'est simplement une solution "basée sur C". C'est approprié, c'est facile, et vous n'avez pas besoin d'écrire beaucoup de code supplémentaire :-)
Non pas que je n'aime pas C, mais strtok n'est pas thread-safe, et vous devez être certain que la chaîne que vous lui envoyez contient un caractère nul pour éviter un éventuel débordement de tampon.
tloach
11
Il y a strtok_r, mais c'était une question C ++.
contrat du professeur Falken a été rompu
3
@tloach: dans le compilateur MS C ++, strtok est sûr pour les threads car la variable statique interne est créée sur le TLS (stockage local des threads) (en fait, cela dépend du compilateur)
Ahmed Said
3
@ahmed: thread safe signifie plus que simplement pouvoir exécuter la fonction deux fois dans différents threads. Dans ce cas, si le thread est modifié pendant l'exécution de strtok, il est possible que la chaîne soit valide pendant toute la durée de l'exécution de strtok, mais strtok ne fonctionnera pas correctement car la chaîne a changé, elle a déjà dépassé le caractère nul et va continuez à lire la mémoire jusqu'à ce qu'elle obtienne une violation de sécurité ou trouve un caractère nul. Il s'agit d'un problème avec les fonctions de chaîne C d'origine, si vous ne spécifiez pas de longueur quelque part, vous rencontrez des problèmes.
tloach
4
strtok nécessite un pointeur vers un tableau de caractères à terminaison nulle non const, ce qui n'est pas une créature courante à trouver dans le code c ++ ... quelle est votre façon préférée de la convertir à partir d'une chaîne std ::?
fuzzyTew
106
Un autre moyen rapide consiste à utiliser getline. Quelque chose comme:
J'ai eu des problèmes en utilisant cette technique avec des caractères 0x0A dans la chaîne, ce qui a fait que la boucle while se ferme prématurément. Sinon, c'est une belle solution simple et rapide.
Ryan H.
4
C'est bien, mais il suffit de garder à l'esprit qu'en faisant cela, le délimiteur par défaut '\ n' n'est pas pris en compte. Cet exemple fonctionnera, mais si vous utilisez quelque chose comme: while (getline (inFile, word, '')) où inFile est un objet ifstream contenant plusieurs lignes, vous obtiendrez des résultats amusants.
hackrock
c'est dommage que getline retourne le flux plutôt que la chaîne, ce qui le rend inutilisable dans les listes d'initialisation sans stockage temporaire
fuzzyTew
1
Cool! Pas de boost et C ++ 11, une bonne solution pour ces projets hérités là-bas!
Deqing
1
C'EST la réponse, le nom de la fonction est juste un peu gênant.
Nils
82
Vous pouvez utiliser des flux, des itérateurs et l'algorithme de copie pour le faire assez directement.
#include<string>#include<vector>#include<iostream>#include<istream>#include<ostream>#include<iterator>#include<sstream>#include<algorithm>int main(){
std::string str ="The quick brown fox";// construct a stream from the string
std::stringstream strstr(str);// use stream iterators to copy the stream to the vector as whitespace separated strings
std::istream_iterator<std::string> it(strstr);
std::istream_iterator<std::string> end;
std::vector<std::string> results(it, end);// send the vector to stdout.
std::ostream_iterator<std::string> oit(std::cout);
std::copy(results.begin(), results.end(), oit);}
Je trouve ces std :: irritants à lire .. pourquoi ne pas utiliser "using"?
user35978
80
@Vadi: parce que modifier le post de quelqu'un d'autre est assez intrusif. @pheze: Je préfère laisser la stdfaçon dont je sais d'où vient mon objet, ce n'est qu'une question de style.
Matthieu M.
7
Je comprends votre raison et je pense que c'est en fait un bon choix si cela fonctionne pour vous, mais d'un point de vue pédagogique, je suis d'accord avec Pheze. Il est plus facile de lire et de comprendre un exemple complètement étranger comme celui-ci avec un "using namespace std" en haut car cela nécessite moins d'effort pour interpréter les lignes suivantes ... surtout dans ce cas parce que tout provient de la bibliothèque standard. Vous pouvez rendre la lecture facile et évidente d'où viennent les objets par une série de "using std :: string;" etc. D'autant plus que la fonction est si courte.
cheshirekow
61
Bien que les préfixes "std ::" soient irritants ou laids, il est préférable de les inclure dans le code d'exemple afin qu'il soit complètement clair d'où viennent ces fonctions. S'ils vous dérangent, il est trivial de les remplacer par une «utilisation» après avoir volé l'exemple et revendiqué le vôtre.
dlchambers
20
oui! ce qu'il a dit! les meilleures pratiques consistent à utiliser le préfixe std. Toute grande base de code aura sans aucun doute ses propres bibliothèques et espaces de noms et l'utilisation de "using namespace std" vous donnera des maux de tête lorsque vous commencerez à provoquer des conflits d'espace de noms.
Miek
48
Pas de gens d'infraction, mais pour un problème simple, vous faites des choses façon trop compliquée. Il existe de nombreuses raisons d'utiliser Boost . Mais pour quelque chose d'aussi simple, c'est comme frapper une mouche avec un traîneau 20 #.
void
split(vector<string>& theStringVector,/* Altered/returned value */const string & theString,const string & theDelimiter){
UASSERT( theDelimiter.size(),>,0);// My own ASSERT macro.size_t start =0, end =0;while( end != string::npos){
end = theString.find( theDelimiter, start);// If at end, use length=maxLength. Else use length=end-start.
theStringVector.push_back( theString.substr( start,(end == string::npos)? string::npos : end - start));// If at end, use start=maxSize. Else use start=end+delimiter.
start =(( end >(string::npos - theDelimiter.size()))? string::npos : end + theDelimiter.size());}}
Par exemple (pour le cas de Doug),
#define SHOW(I,X) cout <<"["<<(I)<<"]\t "# X " = \"" << (X) << "\"" << endlint
main(){vector<string> v;
split( v,"A:PEP:909:Inventory Item",":");for(unsignedint i =0; i < v.size(); i++)
SHOW( i, v[i]);}
Et oui, nous aurions pu split () retourner un nouveau vecteur plutôt que d'en passer un. Il est trivial d'envelopper et de surcharger. Mais selon ce que je fais, je trouve souvent préférable de réutiliser des objets préexistants plutôt que d'en créer toujours de nouveaux. (Tant que je n'oublie pas de vider le vecteur entre les deux!)
Pourquoi définir une macro que vous n'utilisez qu'en un seul endroit. Et comment votre UASSERT est-il meilleur que l'assertion standard? Diviser la comparaison en 3 jetons comme celui-ci ne fait rien d'autre que nécessiter plus de virgules que vous n'en auriez besoin autrement.
crelbor
1
Peut-être que la macro UASSERT montre (dans le message d'erreur) la relation réelle entre (et les valeurs de) les deux valeurs comparées? C'est en fait une assez bonne idée, à mon humble avis.
GhassanPL
10
Pouah, pourquoi la std::stringclasse n'inclut-elle pas une fonction split ()?
M. Shickadance
Je pense que la dernière ligne de la boucle while devrait être start = ((end > (theString.size() - theDelimiter.size())) ? string::npos : end + theDelimiter.size());et la boucle while devrait être while (start != string::npos). De plus, je vérifie la sous-chaîne pour m'assurer qu'elle n'est pas vide avant de l'insérer dans le vecteur.
John K
@JohnK Si l'entrée a deux délimiteurs consécutifs, alors clairement la chaîne entre eux est vide et doit être insérée dans le vecteur. Si des valeurs vides ne sont pas acceptables pour un usage particulier, c'est autre chose, mais de telles contraintes à mon humble avis devraient être appliquées en dehors de ce type de fonctions à usage très général.
Lauri Nurmi
46
Une solution utilisant regex_token_iterators:
#include<iostream>#include<regex>#include<string>usingnamespace std;int main(){
string str("The quick brown fox");
regex reg("\\s+");
sregex_token_iterator iter(str.begin(), str.end(), reg,-1);
sregex_token_iterator end;vector<string> vec(iter, end);for(auto a : vec){
cout << a << endl;}}
Cela devrait être la réponse la mieux classée. C'est la bonne façon de le faire en C ++> = 11.
Omnifarious
1
Je suis content d'avoir fait défiler jusqu'à cette réponse (il n'y avait actuellement que 9 votes positifs). C'est exactement à quoi devrait ressembler un code C ++ 11 pour cette tâche!
YePhIcK
Excellente réponse qui ne repose pas sur des bibliothèques externes et utilise des bibliothèques déjà disponibles
Andrew
1
Grande réponse, donnant le plus de flexibilité dans les délimiteurs. Quelques mises en garde: l'utilisation de \ s + regex évite les jetons vides au milieu du texte, mais donne un premier jeton vide si le texte commence par un espace. En outre, l'expression régulière semble lente: sur mon ordinateur portable, pour 20 Mo de texte aléatoire, cela prend 0,6 seconde, contre 0,014 seconde pour strtok, strsep ou la réponse de Parham en utilisant str.find_first_of, ou 0,027 seconde pour Perl ou 0,021 seconde pour Python . Pour un texte court, la vitesse peut ne pas être un problème.
Mark Gates
2
Ok, peut-être que ça a l'air cool, mais c'est clairement une surutilisation des expressions régulières. Raisonnable uniquement si vous ne vous souciez pas des performances.
#include<vector>#include<boost/algorithm/string.hpp>int main(){auto s ="a,b, c ,,e,f,";
std::vector<std::string> fields;
boost::split(fields, s, boost::is_any_of(","));for(constauto& field : fields)
std::cout <<"\""<< field <<"\"\n";return0;}
Il s'agit d'une solution simple en STL (~ 5 lignes!) Utilisant std::findet std::find_first_not_ofqui gère les répétitions du délimiteur (comme les espaces ou les périodes par exemple), ainsi que les délimiteurs de début et de fin:
#include<string>#include<vector>void tokenize(std::string str, std::vector<string>&token_v){size_t start = str.find_first_not_of(DELIMITER), end=start;while(start != std::string::npos){// Find next occurence of delimiter
end = str.find(DELIMITER, start);// Push back the token found into vector
token_v.push_back(str.substr(start, end-start));// Skip all occurences of the delimiter to find new start
start = str.find_first_not_of(DELIMITER, end);}}
C'est un bon mais je pense que vous devez utiliser find_first_of () au lieu de find () pour que cela fonctionne correctement avec plusieurs délimiteurs.
2
@ user755921 plusieurs délimiteurs sont ignorés lors de la recherche de la position de départ avec find_first_not_of.
Débutant
16
pystring est une petite bibliothèque qui implémente un tas de fonctions de chaîne de Python, y compris la méthode de fractionnement:
#include<string>#include<vector>#include"pystring.h"
std::vector<std::string> chunks;
pystring::split("this string", chunks);// also can specify a separator
pystring::split("this-string", chunks,"-");
Wow, vous avez répondu à ma question immédiate et à de nombreuses questions futures. Je comprends que c ++ est puissant. Mais lorsque le fractionnement d'une chaîne entraîne un code source comme les réponses ci-dessus, c'est clairement décourageant. J'aimerais connaître d'autres bibliothèques comme celle-ci qui abaissent les commodités des langages de niveau supérieur.
Ross
wow, vous venez de faire ma journée sérieusement !! ne connaissait pas pystring. cela va me faire gagner beaucoup de temps!
accraze
11
J'ai posté cette réponse pour une question similaire.
Ne réinventez pas la roue. J'ai utilisé un certain nombre de bibliothèques et la plus rapide et la plus flexible que j'ai rencontrée est la suivante: C ++ String Toolkit Library .
Voici un exemple d'utilisation que j'ai publié ailleurs sur le stackoverflow.
#include<iostream>#include<vector>#include<string>#include<strtk.hpp>constchar*whitespace =" \t\r\n\f";constchar*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<std::string> 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<float> 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;}}return0;}
#include<iostream>#include<sstream>usingnamespace std;int main (){
string tmps;
istringstream is ("the dellimiter is the space");while(is.good ()){
is >> tmps;
cout << tmps <<"\n";}return0;}
Cette fonction Tokenize () sautera les jetons vides, par exemple, s'il y a une sous-chaîne "%%" dans la chaîne principale, aucun jeton vide n'est retourné. Il est ignoré.
Sheen
4
Si vous êtes prêt à utiliser C, vous pouvez utiliser la fonction strtok . Vous devez faire attention aux problèmes de multi-threading lors de son utilisation.
Notez que strtok modifie la chaîne que vous vérifiez, vous ne pouvez donc pas l'utiliser sur des chaînes const char * sans faire de copie.
Graeme Perrow
9
Le problème du multithreading est que strtok utilise une variable globale pour garder une trace de l'endroit où il se trouve, donc si vous avez deux threads qui utilisent chacun strtok, vous obtiendrez un comportement non défini.
JohnMcG
@JohnMcG Ou utilisez simplement strtok_sce qui est essentiellement strtokavec un passage d'état explicite.
Matthias
4
Pour des trucs simples, j'utilise simplement ce qui suit:
Avertissement lâche: j'écris un logiciel de traitement de données en temps réel où les données arrivent via des fichiers binaires, des sockets ou un appel API (cartes d'E / S, caméras). Je n'utilise jamais cette fonction pour quelque chose de plus compliqué ou de temps critique que la lecture de fichiers de configuration externes au démarrage.
+1 pour suggérer l'expression régulière, si vous n'avez pas besoin de vitesse de distorsion, c'est la solution la plus flexible, pas encore prise en charge partout mais avec le temps, cela deviendra moins important.
odinthenerd
+1 de moi, j'ai juste essayé <regex> en c ++ 11. Si simple et élégant
StahlRat
4
Beaucoup de suggestions trop compliquées ici. Essayez cette solution simple std :: string:
Ma faute pour avoir donné un mauvais exemple (trop simple). Pour autant que je sache, cela ne fonctionne que lorsque votre délimiteur est un espace blanc.
Si vous recherchez une complexité abstraite en utilisant des fonctionnalités standard, comme le suggère On Freund,strtok c'est une option simple:
vector<string> tokens;for(auto i = strtok(data(str)," "); i !=nullptr; i = strtok(nullptr," ")) tokens.push_back(i);
Si vous n'avez pas accès à C ++ 17, vous devrez remplacer data(str)comme dans cet exemple: http://ideone.com/8kAGoa
Bien que cela ne soit pas démontré dans l'exemple, il strtokn'est pas nécessaire d'utiliser le même délimiteur pour chaque jeton. Parallèlement à cet avantage, il existe cependant plusieurs inconvénients:
strtokne peut pas être utilisé sur plusieurs stringsen même temps: Soit un nullptrdoit être adopté pour continuer tokenizing le courant stringou une nouvelle char*à tokenize doit être adopté (il y a quelques implémentations non standard qui ne supportent ce cependant, comme: strtok_s)
Pour la même raison, strtokne peut pas être utilisé sur plusieurs threads simultanément (cela peut cependant être défini par l'implémentation, par exemple: l'implémentation de Visual Studio est thread-safe )
L'appel strtokmodifie le stringsystème sur lequel il fonctionne, il ne peut donc pas être utilisé sur des chaînes const strings, const char*s ou littérales, pour symboliser l'un d'entre eux avec strtokou pour fonctionner sur un stringcontenu dont le contenu doit être conservé, strdoit être copié, puis la copie peut être opéré
Les méthodes précédentes ne peuvent pas générer un vectorin- tokenized , c'est-à-dire sans les abstraire dans une fonction d'assistance qu'ils ne peuvent pas initialiser const vector<string> tokens. Cette fonctionnalité et la capacité d'accepter tout délimiteur d'espace blanc peuvent être exploitées à l'aide d'un istream_iterator. Par exemple donné: const string str{ "The quick \tbrown \nfox" }nous pouvons le faire:
La construction requise d'un istringstreampour cette option a un coût beaucoup plus élevé que les 2 options précédentes, mais ce coût est généralement caché dans les frais d' stringallocation.
Si aucune des options ci-dessus n'est suffisamment flexible pour vos besoins de tokenisation, l'option la plus flexible utilise regex_token_iteratorbien sûr une flexibilité qui entraîne des dépenses plus importantes, mais là encore, cela est probablement caché dans le stringcoût d'allocation. Supposons par exemple que nous souhaitons effectuer une tokenisation basée sur des virgules non échappées, en mangeant également des espaces blancs, étant donné l'entrée suivante: const string str{ "The ,qu\\,ick ,\tbrown, fox" }nous pouvons le faire:
strtok_sest d'ailleurs la norme C11. strtok_rest une norme POSIX2001. Entre les deux, il existe une version standard réentrante strtokpour la plupart des plateformes.
Andon M. Coleman
@ AndonM.Coleman Mais c'est une question c ++ , et en C ++ #include <cstring>ne comprend que la version c99 de strtok. Donc, mon hypothèse est que vous fournissez simplement ce commentaire comme matériel de support, démontrant la disponibilité spécifique des implémentations des strtokextensions?
Jonathan Mee
1
Simplement que ce n'est pas aussi inhabituel que les gens pourraient le croire. strtok_sest fourni par C11 et en tant qu'extension autonome dans le runtime C de Microsoft. Il y a un peu d'histoire ici où les _sfonctions de Microsoft sont devenues la norme C.
Andon M. Coleman
@ AndonM.Coleman D'accord, je suis avec vous. Évidemment, si c'est dans la norme C11, l'interface et l'implémentation sont soumises à des contraintes qui nécessitent un comportement identique indépendamment de la plate-forme. Maintenant, le seul problème est de s'assurer que la fonction C11 est disponible pour nous sur toutes les plateformes. Espérons que la norme C11 sera quelque chose que C ++ 17 ou C ++ 20 choisira de ramasser.
Jonathan Mee
3
Je sais que cette question a déjà reçu une réponse, mais je souhaite y contribuer. Peut-être que ma solution est un peu simple, mais voici ce que j'ai trouvé:
Il me semble étrange qu'avec tous les nerds soucieux de la vitesse ici sur SO, personne n'a présenté une version qui utilise une table de recherche générée par le temps de compilation pour le délimiteur (exemple d'implémentation plus bas). Utiliser une table de recherche et des itérateurs devrait battre std :: regex en termes d'efficacité, si vous n'avez pas besoin de battre regex, utilisez-le simplement, son standard en C ++ 11 et super flexible.
Certains ont déjà suggéré l'expression régulière, mais pour les noobs, voici un exemple compact qui devrait faire exactement ce que l'OP attend:
std::vector<std::string> split(std::string::const_iterator it, std::string::const_iterator end, std::regex e = std::regex{"\\w+"}){
std::smatch m{};
std::vector<std::string> ret{};while(std::regex_search (it,end,m,e)){
ret.emplace_back(m.str());
std::advance(it, m.position()+ m.length());//next start position = match position + match length}return ret;}
std::vector<std::string> split(const std::string &s, std::regex e = std::regex{"\\w+"}){//comfort version calls flexible versionreturn split(s.cbegin(), s.cend(), std::move(e));}int main (){
std::string str {"Some people, excluding those present, have been compile time constants - since puberty."};auto v = split(str);for(constauto&s:v){
std::cout << s << std::endl;}
std::cout <<"crazy version:"<< std::endl;
v = split(str, std::regex{"[^e]+"});//using e as delim shows flexibilityfor(constauto&s:v){
std::cout << s << std::endl;}return0;}
Si nous devons être plus rapides et accepter la contrainte que tous les caractères doivent être 8 bits, nous pouvons faire une table de recherche au moment de la compilation en utilisant la métaprogrammation:
template<bool...>structBoolSequence{};//just here to hold boolstemplate<char...>structCharSequence{};//just here to hold charstemplate<typename T,char C>structContains;//generictemplate<charFirst,char...Cs,charMatch>//not first specializationstructContains<CharSequence<First,Cs...>,Match>:Contains<CharSequence<Cs...>,Match>{};//strip first and increase indextemplate<charFirst,char...Cs>//is first specializationstructContains<CharSequence<First,Cs...>,First>: std::true_type {};template<charMatch>//not found specializationstructContains<CharSequence<>,Match>: std::false_type{};template<int I,typename T,typename U>structMakeSequence;//generictemplate<int I,bool...Bs,typename U>structMakeSequence<I,BoolSequence<Bs...>, U>://not lastMakeSequence<I-1,BoolSequence<Contains<U,I-1>::value,Bs...>, U>{};template<bool...Bs,typename U>structMakeSequence<0,BoolSequence<Bs...>,U>{//last usingType=BoolSequence<Bs...>;};template<typename T>structBoolASCIITable;template<bool...Bs>structBoolASCIITable<BoolSequence<Bs...>>{/* could be made constexpr but not yet supported by MSVC */staticbool isDelim(constchar c){staticconstbool table[256]={Bs...};return table[static_cast<int>(c)];}};usingDelims=CharSequence<'.',',',' ',':','\n'>;//list your custom delimiters hereusingTable=BoolASCIITable<typenameMakeSequence<256,BoolSequence<>,Delims>::Type>;
Avec cela en place, faire une getNextTokenfonction est facile:
template<typename T_It>
std::pair<T_It,T_It> getNextToken(T_It begin,T_It end){
begin = std::find_if(begin,end,std::not1(Table{}));//find first non delim or endauto second = std::find_if(begin,end,Table{});//find first delim or endreturn std::make_pair(begin,second);}
Son utilisation est également simple:
int main(){
std::string s{"Some people, excluding those present, have been compile time constants - since puberty."};auto it = std::begin(s);auto end = std::end(s);while(it != std::end(s)){auto token = getNextToken(it,end);
std::cout << std::string(token.first,token.second)<< std::endl;
it = token.second;}return0;}
Est-il possible de tokennize avec un délimiteur de chaîne?
Galigator
cette version n'est optimisée que pour les délimiteurs à un seul caractère, l'utilisation d'une table de recherche n'est pas adaptée aux délimiteurs à plusieurs caractères (chaîne), ce qui rend son regex plus difficile à battre en termes d'efficacité.
odinthenerd
1
vous pouvez profiter de boost :: make_find_iterator. Quelque chose de similaire à ceci:
template<typename CH>inlinevector< basic_string<CH>> tokenize(const basic_string<CH>&Input,const basic_string<CH>&Delimiter,bool remove_empty_token
){typedeftypename basic_string<CH>::const_iteratorstring_iterator_t;typedef boost::find_iterator<string_iterator_t>string_find_iterator_t;vector< basic_string<CH>>Result;string_iterator_t it =Input.begin();string_iterator_t it_end =Input.end();for(string_find_iterator_t i = boost::make_find_iterator(Input, boost::first_finder(Delimiter, boost::is_equal()));
i !=string_find_iterator_t();++i){if(remove_empty_token){if(it != i->begin())Result.push_back(basic_string<CH>(it,i->begin()));}elseResult.push_back(basic_string<CH>(it,i->begin()));
it = i->end();}if(it != it_end)Result.push_back(basic_string<CH>(it,it_end));returnResult;}
Voici mon couteau Swiss® Army de jetons de chaîne pour séparer les chaînes par des espaces, en tenant compte des chaînes enveloppées de guillemets simples et doubles ainsi que de supprimer ces caractères des résultats. J'ai utilisé RegexBuddy 4.x pour générer la plupart des extraits de code, mais j'ai ajouté une gestion personnalisée pour supprimer les devis et quelques autres choses.
Les votes (descendants) peuvent être aussi constructifs que les votes positifs, mais pas lorsque vous ne laissez pas de commentaires sur les raisons pour lesquelles ...
kayleeFrye_onDeck
1
Je vous ai égalisé, mais cela pourrait être parce que le code semble assez intimidant pour le programmeur googler `` comment diviser une chaîne '' en particulier sans documentation
mattshu
Merci @mattshu! Est-ce que ce sont les segments d'expression régulière qui le rendent intimidant ou autre chose?
kayleeFrye_onDeck
0
Si la longueur maximale de la chaîne d'entrée à tokeniser est connue, on peut l'exploiter et implémenter une version très rapide. J'esquisse l'idée de base ci-dessous, qui a été inspirée à la fois par strtok () et la structure de données "tableau de suffixes" décrit la 2ème édition de "Programmation Perls" de Jon Bentley, chapitre 15. La classe C ++ dans ce cas ne donne qu'une certaine organisation et commodité utile. L'implémentation illustrée peut être facilement étendue pour supprimer les caractères d'espacement avant et arrière dans les jetons.
Fondamentalement, on peut remplacer les caractères de séparation par des caractères «\ 0» de terminaison de chaîne et définir des pointeurs sur les jetons avec la chaîne modifiée. Dans le cas extrême où la chaîne se compose uniquement de séparateurs, on obtient la longueur de chaîne plus 1 jetons vides résultants. Il est pratique de dupliquer la chaîne à modifier.
En tête de fichier:
classTextLineSplitter{public:TextLineSplitter(constsize_t max_line_len );~TextLineSplitter();voidSplitLine(constchar*line,constchar sep_char =',',);inlinesize_tNumTokens(void)const{return mNumTokens;}constchar*GetToken(constsize_t token_idx )const{
assert( token_idx < mNumTokens );return mTokens[ token_idx ];}private:constsize_t mStorageSize;char*mBuff;char**mTokens;size_t mNumTokens;inlinevoidResetContent(void){
memset( mBuff,0, mStorageSize );// mark all items as empty:
memset( mTokens,0, mStorageSize *sizeof(char*));// reset counter for found items:
mNumTokens =0L;}};
// create an instance capable of splitting strings up to 1000 chars long:TextLineSplitter spl(1000);
spl.SplitLine("Item1,,Item2,Item3");for(size_t i =0; i < spl.NumTokens(); i++){
printf("%s\n", spl.GetToken( i ));}
boost::tokenizerest votre ami, mais envisagez de rendre votre code portable en référence aux problèmes d'internationalisation (i18n) en utilisant wstring/ wchar_tau lieu de l'héritage string/ chartypes.
#include<iostream>#include<boost/tokenizer.hpp>#include<string>usingnamespace std;usingnamespace boost;typedef tokenizer<char_separator<wchar_t>,
wstring::const_iterator, wstring>Tok;int main(){
wstring s;while(getline(wcin, s)){
char_separator<wchar_t> sep(L" ");// list of separator charactersTok tok(s, sep);for(Tok::iterator beg = tok.begin(); beg != tok.end();++beg){
wcout <<*beg << L"\t";// output (or store in vector)}
wcout << L"\n";}return0;}
"hérité" n'est certainement pas correct et wchar_test un type dépendant de la mise en œuvre horrible que personne ne devrait utiliser sauf si absolument nécessaire.
CoffeeandCode
L'utilisation de wchar_t ne résout pas automatiquement les problèmes d'i18n. Vous utilisez des encodages pour résoudre ce problème. Si vous divisez une chaîne par un délimiteur, cela implique que le délimiteur n'entre pas en collision avec le contenu codé d'un jeton à l'intérieur de la chaîne. Il peut être nécessaire de s'échapper, etc. wchar_t n'est pas une solution magique à cela.
yonil
0
Le code C ++ simple (C ++ 98 standard), accepte plusieurs délimiteurs (spécifiés dans une chaîne std ::), utilise uniquement des vecteurs, des chaînes et des itérateurs.
#include<iostream>#include<vector>#include<string>#include<stdexcept>
std::vector<std::string>
split(const std::string& str,const std::string& delim){
std::vector<std::string> result;if(str.empty())throw std::runtime_error("Can not tokenize an empty string!");
std::string::const_iterator begin, str_it;
begin = str_it = str.begin();do{while(delim.find(*str_it)== std::string::npos && str_it != str.end())
str_it++;// find the position of the first delimiter in str
std::string token = std::string(begin, str_it);// grab the tokenif(!token.empty())// empty token only when str starts with a delimiter
result.push_back(token);// push the token into a vector<string>while(delim.find(*str_it)!= std::string::npos && str_it != str.end())
str_it++;// ignore the additional consecutive delimiters
begin = str_it;// process the remaining tokens}while(str_it != str.end());return result;}int main(){
std::string test_string =".this is.a.../.simple;;test;;;END";
std::string delim ="; ./";// string containing the delimiters
std::vector<std::string> tokens = split(test_string, delim);for(std::vector<std::string>::const_iterator it = tokens.begin();
it != tokens.end(); it++)
std::cout <<*it << std::endl;}
Réponses:
Les algorithmes de bibliothèque standard C ++ sont assez universellement basés autour d'itérateurs plutôt que de conteneurs concrets. Malheureusement, cela rend difficile la fourniture d'une
split
fonction de type Java dans la bibliothèque standard C ++, même si personne ne prétend que ce serait pratique. Mais quel serait son type de retour?std::vector<std::basic_string<…>>
? Peut-être, mais alors nous sommes obligés d'effectuer des allocations (potentiellement redondantes et coûteuses).Au lieu de cela, C ++ offre une multitude de façons de diviser les chaînes en fonction de délimiteurs arbitrairement complexes, mais aucune d'entre elles n'est aussi bien encapsulée que dans d'autres langages. Les nombreuses façons de remplir des articles de blog entiers .
À sa plus simple expression, vous pouvez répéter l’utilisation
std::string::find
jusqu’à ce que vous frappiezstd::string::npos
et extraire le contenu à l’aide destd::string::substr
.Une version plus fluide (et idiomatique, mais basique) pour le fractionnement sur un espace blanc utiliserait
std::istringstream
:À l'aide de
std::istream_iterator
s , le contenu du flux de chaînes peut également être copié dans un vecteur à l'aide de son constructeur de plage d'itérateur.Plusieurs bibliothèques (telles que Boost.Tokenizer ) proposent des tokenisers spécifiques.
Un fractionnement plus avancé nécessite des expressions régulières. C ++ fournit notamment
std::regex_token_iterator
à cet effet:la source
le classe de tokenizer Boost peut rendre ce genre de chose assez simple:
Mis à jour pour C ++ 11:
la source
char_separator
constructeur (drop_empty_tokens
c'est la valeur par défaut, l'alternative l'estkeep_empty_tokens
)..h
pour les en-têtes C)En voici une très simple:
la source
Utilisez strtok. À mon avis, il n'est pas nécessaire de créer une classe autour de la tokenisation à moins que strtok ne vous fournisse pas ce dont vous avez besoin. Ce n'est peut-être pas le cas, mais en 15 ans et plus d'écriture de divers codes d'analyse en C et C ++, j'ai toujours utilisé strtok. Voici un exemple
Quelques mises en garde (qui pourraient ne pas convenir à vos besoins). La chaîne est "détruite" au cours du processus, ce qui signifie que les caractères EOS sont placés en ligne dans les points de délimitation. Une utilisation correcte peut vous obliger à créer une version non constante de la chaîne. Vous pouvez également modifier la liste des délimiteurs en cours d'analyse.
À mon avis, le code ci-dessus est beaucoup plus simple et plus facile à utiliser que d'écrire une classe distincte pour lui. Pour moi, c'est l'une de ces fonctions que le langage fournit et il le fait bien et proprement. C'est simplement une solution "basée sur C". C'est approprié, c'est facile, et vous n'avez pas besoin d'écrire beaucoup de code supplémentaire :-)
la source
Un autre moyen rapide consiste à utiliser
getline
. Quelque chose comme:Si vous le souhaitez, vous pouvez créer une
split()
méthode simple renvoyant unvector<string>
, ce qui est vraiment utile.la source
Vous pouvez utiliser des flux, des itérateurs et l'algorithme de copie pour le faire assez directement.
la source
std
façon dont je sais d'où vient mon objet, ce n'est qu'une question de style.Pas de gens d'infraction, mais pour un problème simple, vous faites des choses façon trop compliquée. Il existe de nombreuses raisons d'utiliser Boost . Mais pour quelque chose d'aussi simple, c'est comme frapper une mouche avec un traîneau 20 #.
Par exemple (pour le cas de Doug),
Et oui, nous aurions pu split () retourner un nouveau vecteur plutôt que d'en passer un. Il est trivial d'envelopper et de surcharger. Mais selon ce que je fais, je trouve souvent préférable de réutiliser des objets préexistants plutôt que d'en créer toujours de nouveaux. (Tant que je n'oublie pas de vider le vecteur entre les deux!)
Référence: http://www.cplusplus.com/reference/string/string/ .
(J'écrivais à l'origine une réponse à la question de Doug: modification et extraction de chaînes C ++ basées sur des séparateurs (fermé) . Mais puisque Martin York a fermé cette question avec un pointeur ici ... je vais simplement généraliser mon code.)
la source
std::string
classe n'inclut-elle pas une fonction split ()?start = ((end > (theString.size() - theDelimiter.size())) ? string::npos : end + theDelimiter.size());
et la boucle while devrait êtrewhile (start != string::npos)
. De plus, je vérifie la sous-chaîne pour m'assurer qu'elle n'est pas vide avant de l'insérer dans le vecteur.Une solution utilisant
regex_token_iterator
s:la source
Boost a une forte fonction de partage: boost :: algorithm :: split .
Exemple de programme:
Production:
la source
Je sais que vous avez demandé une solution C ++, mais vous pourriez considérer cela utile:
Qt
L'avantage par rapport à Boost dans cet exemple est qu'il s'agit d'un mappage direct un à un avec le code de votre message.
En savoir plus sur la documentation Qt
la source
Voici un exemple de classe de tokenizer qui pourrait faire ce que vous voulez
Exemple:
la source
Il s'agit d'une solution simple en STL (~ 5 lignes!) Utilisant
std::find
etstd::find_first_not_of
qui gère les répétitions du délimiteur (comme les espaces ou les périodes par exemple), ainsi que les délimiteurs de début et de fin:Essayez-le en direct !
la source
pystring est une petite bibliothèque qui implémente un tas de fonctions de chaîne de Python, y compris la méthode de fractionnement:
la source
J'ai posté cette réponse pour une question similaire.
Ne réinventez pas la roue. J'ai utilisé un certain nombre de bibliothèques et la plus rapide et la plus flexible que j'ai rencontrée est la suivante: C ++ String Toolkit Library .
Voici un exemple d'utilisation que j'ai publié ailleurs sur le stackoverflow.
la source
Vérifiez cet exemple. Cela pourrait vous aider ..
la source
while ( is >> tmps ) { std::cout << tmps << "\n"; }
MFC / ATL a un très joli tokenizer. Depuis MSDN:
la source
Si vous êtes prêt à utiliser C, vous pouvez utiliser la fonction strtok . Vous devez faire attention aux problèmes de multi-threading lors de son utilisation.
la source
strtok_s
ce qui est essentiellementstrtok
avec un passage d'état explicite.Pour des trucs simples, j'utilise simplement ce qui suit:
Avertissement lâche: j'écris un logiciel de traitement de données en temps réel où les données arrivent via des fichiers binaires, des sockets ou un appel API (cartes d'E / S, caméras). Je n'utilise jamais cette fonction pour quelque chose de plus compliqué ou de temps critique que la lecture de fichiers de configuration externes au démarrage.
la source
Vous pouvez simplement utiliser une bibliothèque d'expressions régulières et résoudre cela en utilisant des expressions régulières.
Utilisez l'expression (\ w +) et la variable dans \ 1 (ou $ 1 selon l'implémentation de la bibliothèque d'expressions régulières).
la source
Beaucoup de suggestions trop compliquées ici. Essayez cette solution simple std :: string:
la source
Je pensais que c'était pour cela que l'
>>
opérateur sur les flux de chaînes:la source
La réponse d'Adam Pierce fournit un jeton tourné à la main prenant en a
const char*
. C'est un peu plus problématique avec les itérateurs car l' incrémentation de l'string
itérateur de fin n'est pas définie . Cela dit, étant donné questring str{ "The quick brown fox" }
nous pouvons certainement y parvenir:Live Example
Si vous recherchez une complexité abstraite en utilisant des fonctionnalités standard, comme le suggère On Freund,
strtok
c'est une option simple:Si vous n'avez pas accès à C ++ 17, vous devrez remplacer
data(str)
comme dans cet exemple: http://ideone.com/8kAGoaBien que cela ne soit pas démontré dans l'exemple, il
strtok
n'est pas nécessaire d'utiliser le même délimiteur pour chaque jeton. Parallèlement à cet avantage, il existe cependant plusieurs inconvénients:strtok
ne peut pas être utilisé sur plusieursstrings
en même temps: Soit unnullptr
doit être adopté pour continuer tokenizing le courantstring
ou une nouvellechar*
à tokenize doit être adopté (il y a quelques implémentations non standard qui ne supportent ce cependant, comme:strtok_s
)strtok
ne peut pas être utilisé sur plusieurs threads simultanément (cela peut cependant être défini par l'implémentation, par exemple: l'implémentation de Visual Studio est thread-safe )strtok
modifie lestring
système sur lequel il fonctionne, il ne peut donc pas être utilisé sur des chaînesconst string
s,const char*
s ou littérales, pour symboliser l'un d'entre eux avecstrtok
ou pour fonctionner sur unstring
contenu dont le contenu doit être conservé,str
doit être copié, puis la copie peut être opéréc ++ 20nous fournit
split_view
pour tokeniser les chaînes, de manière non destructive: https://topanswers.xyz/cplusplus?q=749#a874Les méthodes précédentes ne peuvent pas générer un
vector
in- tokenized , c'est-à-dire sans les abstraire dans une fonction d'assistance qu'ils ne peuvent pas initialiserconst vector<string> tokens
. Cette fonctionnalité et la capacité d'accepter tout délimiteur d'espace blanc peuvent être exploitées à l'aide d'unistream_iterator
. Par exemple donné:const string str{ "The quick \tbrown \nfox" }
nous pouvons le faire:Live Example
La construction requise d'un
istringstream
pour cette option a un coût beaucoup plus élevé que les 2 options précédentes, mais ce coût est généralement caché dans les frais d'string
allocation.Si aucune des options ci-dessus n'est suffisamment flexible pour vos besoins de tokenisation, l'option la plus flexible utilise
regex_token_iterator
bien sûr une flexibilité qui entraîne des dépenses plus importantes, mais là encore, cela est probablement caché dans lestring
coût d'allocation. Supposons par exemple que nous souhaitons effectuer une tokenisation basée sur des virgules non échappées, en mangeant également des espaces blancs, étant donné l'entrée suivante:const string str{ "The ,qu\\,ick ,\tbrown, fox" }
nous pouvons le faire:Live Example
la source
strtok_s
est d'ailleurs la norme C11.strtok_r
est une norme POSIX2001. Entre les deux, il existe une version standard réentrantestrtok
pour la plupart des plateformes.#include <cstring>
ne comprend que la version c99 destrtok
. Donc, mon hypothèse est que vous fournissez simplement ce commentaire comme matériel de support, démontrant la disponibilité spécifique des implémentations desstrtok
extensions?strtok_s
est fourni par C11 et en tant qu'extension autonome dans le runtime C de Microsoft. Il y a un peu d'histoire ici où les_s
fonctions de Microsoft sont devenues la norme C.Je sais que cette question a déjà reçu une réponse, mais je souhaite y contribuer. Peut-être que ma solution est un peu simple, mais voici ce que j'ai trouvé:
Veuillez commenter s'il existe une meilleure approche de quelque chose dans mon code ou si quelque chose ne va pas.
MISE À JOUR: ajout d'un séparateur générique
la source
Voici une approche qui vous permet de contrôler si les jetons vides sont inclus (comme strsep) ou exclus (comme strtok).
la source
Il me semble étrange qu'avec tous les nerds soucieux de la vitesse ici sur SO, personne n'a présenté une version qui utilise une table de recherche générée par le temps de compilation pour le délimiteur (exemple d'implémentation plus bas). Utiliser une table de recherche et des itérateurs devrait battre std :: regex en termes d'efficacité, si vous n'avez pas besoin de battre regex, utilisez-le simplement, son standard en C ++ 11 et super flexible.
Certains ont déjà suggéré l'expression régulière, mais pour les noobs, voici un exemple compact qui devrait faire exactement ce que l'OP attend:
Si nous devons être plus rapides et accepter la contrainte que tous les caractères doivent être 8 bits, nous pouvons faire une table de recherche au moment de la compilation en utilisant la métaprogrammation:
Avec cela en place, faire une
getNextToken
fonction est facile:Son utilisation est également simple:
Voici un exemple en direct: http://ideone.com/GKtkLQ
la source
vous pouvez profiter de boost :: make_find_iterator. Quelque chose de similaire à ceci:
la source
Voici mon couteau Swiss® Army de jetons de chaîne pour séparer les chaînes par des espaces, en tenant compte des chaînes enveloppées de guillemets simples et doubles ainsi que de supprimer ces caractères des résultats. J'ai utilisé RegexBuddy 4.x pour générer la plupart des extraits de code, mais j'ai ajouté une gestion personnalisée pour supprimer les devis et quelques autres choses.
la source
Si la longueur maximale de la chaîne d'entrée à tokeniser est connue, on peut l'exploiter et implémenter une version très rapide. J'esquisse l'idée de base ci-dessous, qui a été inspirée à la fois par strtok () et la structure de données "tableau de suffixes" décrit la 2ème édition de "Programmation Perls" de Jon Bentley, chapitre 15. La classe C ++ dans ce cas ne donne qu'une certaine organisation et commodité utile. L'implémentation illustrée peut être facilement étendue pour supprimer les caractères d'espacement avant et arrière dans les jetons.
Fondamentalement, on peut remplacer les caractères de séparation par des caractères «\ 0» de terminaison de chaîne et définir des pointeurs sur les jetons avec la chaîne modifiée. Dans le cas extrême où la chaîne se compose uniquement de séparateurs, on obtient la longueur de chaîne plus 1 jetons vides résultants. Il est pratique de dupliquer la chaîne à modifier.
En tête de fichier:
Fichier d'implémentation:
Un scénario d'utilisation serait:
production:
la source
boost::tokenizer
est votre ami, mais envisagez de rendre votre code portable en référence aux problèmes d'internationalisation (i18n) en utilisantwstring
/wchar_t
au lieu de l'héritagestring
/char
types.la source
wchar_t
est un type dépendant de la mise en œuvre horrible que personne ne devrait utiliser sauf si absolument nécessaire.Le code C ++ simple (C ++ 98 standard), accepte plusieurs délimiteurs (spécifiés dans une chaîne std ::), utilise uniquement des vecteurs, des chaînes et des itérateurs.
la source