J'essaie d'itérer sur les mots d'une chaîne.
On peut supposer que la chaîne est composée de mots séparés par des espaces.
Notez que je ne suis pas intéressé par les fonctions de chaîne C ou ce genre de manipulation / accès aux caractères. Veuillez également donner la priorité à l'élégance sur l'efficacité dans votre réponse.
La meilleure solution que j'ai en ce moment est:
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main()
{
string s = "Somewhere down the road";
istringstream iss(s);
do
{
string subs;
iss >> subs;
cout << "Substring: " << subs << endl;
} while (iss);
}
Existe-t-il une manière plus élégante de procéder?
while (iss) { string subs; iss >> subs; cout << "Substring: " << sub << endl; }
string sub; while (iss >> sub) cout << "Substring: " << sub << '\n';
Réponses:
Pour ce que ça vaut, voici une autre façon d'extraire des jetons d'une chaîne d'entrée, en ne s'appuyant que sur les fonctionnalités de bibliothèque standard. C'est un exemple de la puissance et de l'élégance derrière le design de la STL.
Au lieu de copier les jetons extraits dans un flux de sortie, on pourrait les insérer dans un conteneur, en utilisant le même
copy
algorithme générique .... ou créez
vector
directement:la source
J'utilise ceci pour diviser la chaîne par un délimiteur. Le premier met les résultats dans un vecteur préconstruit, le second renvoie un nouveau vecteur.
Notez que cette solution n'ignore pas les jetons vides, donc les éléments suivants trouveront 4 éléments, dont l'un est vide:
la source
empty()
vérifiez:if (!item.empty()) elems.push_back(item)
->
?f(split(s, d, v))
tout en bénéficiant d'un pré-allouévector
si vous le souhaitez.Une solution possible en utilisant Boost pourrait être:
Cette approche pourrait être encore plus rapide que l'
stringstream
approche. Et comme il s'agit d'une fonction de modèle générique, elle peut être utilisée pour diviser d'autres types de chaînes (wchar, etc. ou UTF-8) en utilisant toutes sortes de délimiteurs.Consultez la documentation pour plus de détails.
la source
la source
getline
dans lawhile
condition par exemple pour diviser par des virgules, utilisezwhile(getline(ss, buff, ','))
.Pour ceux avec qui il n'est pas bon de sacrifier toute l'efficacité pour la taille du code et de voir "efficace" comme un type d'élégance, ce qui suit devrait frapper un point idéal (et je pense que la classe de conteneur de modèle est un ajout incroyablement élégant.):
Je choisis généralement d'utiliser les
std::vector<std::string>
types comme deuxième paramètre (ContainerT
) ... maislist<>
c'est beaucoup plus rapide quevector<>
lorsque l'accès direct n'est pas nécessaire, et vous pouvez même créer votre propre classe de chaînes et utiliser quelque chose commestd::list<subString>
oùsubString
ne fait aucune copie pour une vitesse incroyable augmente.C'est plus du double de la jeton le plus rapide de cette page et presque 5 fois plus rapide que d'autres. De plus, avec les types de paramètres parfaits, vous pouvez éliminer toutes les copies de chaînes et de listes pour des augmentations de vitesse supplémentaires.
De plus, il ne fait pas le retour de résultat (extrêmement inefficace), mais plutôt il passe les jetons comme référence, vous permettant ainsi de créer des jetons en utilisant plusieurs appels si vous le souhaitez.
Enfin, il vous permet de spécifier s'il faut rogner les jetons vides des résultats via un dernier paramètre facultatif.
Tout ce dont il a besoin, c'est
std::string
... les autres sont facultatifs. Il n'utilise pas de flux ou la bibliothèque de boost, mais est suffisamment flexible pour pouvoir accepter naturellement certains de ces types étrangers.la source
typedef ContainerT Base; typedef typename Base::value_type ValueType; typedef typename ValueType::size_type SizeType;
Ensuite, remplacez value_type et size_types en conséquence.trimEmpty = true
. Gardez à l'esprit que ce"abo"
n'est pas un délimiteur dans cette réponse, mais la liste des caractères du délimiteur. Il serait simple de le modifier pour prendre une seule chaîne de caractères de délimitation (je pense que celastr.find_first_of
devrait changerstr.find_first
, mais je peux me tromper ... je ne peux pas tester)Voici une autre solution. Il est compact et raisonnablement efficace:
Il peut facilement être modélisé pour gérer les séparateurs de chaînes, les chaînes larges, etc.
Notez que le fractionnement
""
entraîne une seule chaîne vide et le fractionnement","
(c'est-à-dire sep) entraîne deux chaînes vides.Il peut également être facilement étendu pour ignorer les jetons vides:
Si le fractionnement d'une chaîne à plusieurs délimiteurs tout en ignorant les jetons vides est souhaité, cette version peut être utilisée:
la source
C'est ma façon préférée de parcourir une chaîne. Vous pouvez faire ce que vous voulez par mot.
la source
word
tant quechar
?stringstream ss("Hello World, this is*@#&$(@ a string"); char c; while(ss >> c) cout << c;
Ceci est similaire à la question Stack Overflow Comment puis-je tokeniser une chaîne en C ++? .
la source
J'aime ce qui suit, car il met les résultats dans un vecteur, prend en charge une chaîne comme délimiteur et donne le contrôle sur la conservation des valeurs vides. Mais ça n'a pas l'air aussi bien alors.
Bien sûr, Boost en a un
split()
qui fonctionne partiellement comme ça. Et, si par `` espace blanc '', vous voulez vraiment dire tout type d'espace blanc, utiliser la division de Boost avec desis_any_of()
œuvres géniales.la source
La STL ne dispose pas déjà d'une telle méthode.
Cependant, vous pouvez soit utiliser la
strtok()
fonction de C en utilisant lestd::string::c_str()
membre, soit écrire la vôtre. Voici un exemple de code que j'ai trouvé après une recherche rapide sur Google ( "STL string split" ):Pris à partir de: http://oopweb.com/CPP/Documents/CPPHOWTO/Volume/C++Programming-HOWTO-7.html
Si vous avez des questions sur l'exemple de code, laissez un commentaire et je vous expliquerai.
Et ce n'est pas parce qu'il n'implémente pas un
typedef
itérateur appelé ou une surcharge que l'<<
opérateur est un mauvais code. J'utilise les fonctions C assez fréquemment. Par exemple,printf
et lesscanf
deux sont plus rapides questd::cin
etstd::cout
(de manière significative), lefopen
syntaxe est beaucoup plus conviviale pour les types binaires, et ils ont également tendance à produire des EXE plus petits.Ne soyez pas vendu avec cette offre "Élégance sur performance" .
la source
Voici une fonction partagée qui:
ignore les jetons vides (peut facilement être modifié)
Exemple d'utilisation:
la source
J'ai une solution en 2 lignes à ce problème:
Ensuite, au lieu d'imprimer, vous pouvez le mettre dans un vecteur.
la source
Encore un autre moyen flexible et rapide
Pour l'utiliser avec un vecteur de chaînes (Edit: Puisque quelqu'un a indiqué de ne pas hériter des classes STL ... hrmf;)):
C'est ça! Et ce n'est qu'une façon d'utiliser le tokenizer, comme la façon de compter les mots:
Limité par l'imagination;)
la source
Appender
note "Pourquoi ne devrions-nous pas hériter d'une classe des classes STL?"Voici une solution simple qui utilise uniquement la bibliothèque regex standard
L'argument regex permet de vérifier plusieurs arguments (espaces, virgules, etc.)
Je ne vérifie généralement que pour séparer les espaces et les virgules, j'ai donc également cette fonction par défaut:
Les
"[\\s,]+"
vérifications des espaces (\\s
) et des virgules (,
).Notez que si vous souhaitez diviser
wstring
au lieu destring
,std::regex
enstd::wregex
sregex_token_iterator
enwsregex_token_iterator
Remarque, vous pouvez également vouloir prendre l'argument chaîne par référence, selon votre compilateur.
la source
R"([\s,]+)"
.Utiliser
std::stringstream
comme vous travaillez parfaitement bien et faites exactement ce que vous vouliez. Si vous cherchez simplement une manière différente de faire les choses, vous pouvez utiliserstd::find()
/std::find_first_of()
etstd::string::substr()
.Voici un exemple:
la source
prev_pos = pos += delimiter.length();
Si vous aimez utiliser le boost, mais souhaitez utiliser une chaîne entière comme délimiteur (au lieu de caractères uniques comme dans la plupart des solutions proposées précédemment), vous pouvez utiliser le
boost_split_iterator
.Exemple de code comprenant un modèle pratique:
la source
Voici une solution regex qui utilise uniquement la bibliothèque regex standard. (Je suis un peu rouillé, donc il peut y avoir quelques erreurs de syntaxe, mais c'est au moins l'idée générale)
la source
Il y a une fonction nommée
strtok
.la source
strtok
est de la bibliothèque standard C, pas C ++. Il n'est pas sûr de l'utiliser dans des programmes multithread. Il modifie la chaîne d'entrée.strtok
alors qu'un autre thread est encore en cours de traitement, ce pointeur de caractère sera remplacé et les deux threads auront alors des résultats incorrects. mkssoftware.com/docs/man3/strtok.3.aspLe flux de chaînes peut être pratique si vous devez analyser la chaîne par des symboles non spatiaux:
la source
Jusqu'à présent, j'ai utilisé celui de Boost , mais j'avais besoin de quelque chose qui n'en dépendait pas, alors je suis arrivé à ceci:
Un bon point est qu'en
separators
vous pouvez passer plus d'un caractère.la source
J'ai roulé le mien en utilisant strtok et utilisé boost pour diviser une chaîne. La meilleure méthode que j'ai trouvée est la bibliothèque C ++ String Toolkit . Il est incroyablement flexible et rapide.
La boîte à outils a beaucoup plus de flexibilité que cet exemple simple ne le montre, mais son utilité pour analyser une chaîne en éléments utiles est incroyable.
la source
Court et élégant
peut utiliser n'importe quelle chaîne comme délimiteur, peut également être utilisé avec des données binaires (std :: string prend en charge les données binaires, y compris les valeurs nulles)
en utilisant:
production:
la source
J'ai fait cela parce que j'avais besoin d'un moyen facile de diviser les chaînes et les chaînes basées sur c ... J'espère que quelqu'un d'autre peut également le trouver utile. De plus, il ne repose pas sur des jetons et vous pouvez utiliser des champs comme délimiteurs, ce qui est une autre clé dont j'avais besoin.
Je suis sûr que des améliorations peuvent être apportées pour améliorer encore son élégance et veuillez le faire par tous les moyens
StringSplitter.hpp:
StringSplitter.cpp:
Exemples:
Sortira:
Ceci
est
un
exemple de
chaîne
Pour conserver les entrées vides (par défaut les vides seront exclus):
Le but était de la rendre similaire à la méthode Split () de C # où le fractionnement d'une chaîne est aussi simple que:
J'espère que quelqu'un d'autre pourra trouver cela aussi utile que moi.
la source
Et ça:
la source
Cette réponse prend la chaîne et la place dans un vecteur de chaînes. Il utilise la bibliothèque boost.
la source
Voici une autre façon de le faire ..
la source
J'aime utiliser les méthodes boost / regex pour cette tâche car elles offrent une flexibilité maximale pour spécifier les critères de fractionnement.
la source
Récemment, j'ai dû diviser un mot en forme de chameau en sous-mots. Il n'y a pas de délimiteurs, juste des caractères supérieurs.
Par exemple, cela divise "AQueryTrades" en "A", "Query" et "Trades". La fonction fonctionne avec des cordes étroites et larges. Parce qu'il respecte les paramètres régionaux actuels, il divise "RaumfahrtÜberwachungsVerordnung" en "Raumfahrt", "Überwachungs" et "Verordnung".
La note
std::upper
doit être vraiment passée comme argument de modèle de fonction. Ensuite, le plus généralisé de cette fonction peut se diviser en délimiteurs comme","
,";"
ou" "
trop.la source
std::isupper
pouvaient être passés en argument, nonstd::upper
. Deuxième mettre untypename
avant leString::const_iterator
.la source
Utilisation
std::string_view
etrange-v3
bibliothèque d' Eric Niebler :https://wandbox.org/permlink/kW5lwRCL1pxjp2pW
En utilisant une
for
boucle de plage au lieu d'unranges::for_each
algorithme:la source