IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Un split "intelligent" ?


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre émérite Avatar de ctxnop
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2007
    Messages
    858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2007
    Messages : 858
    Par défaut Un split "intelligent" ?
    Bonjour,
    Je cherche à faire une fonction pour splitter une chaine, mais je voudrais quelque chose d'un peu plus intelligent qu'un simple délimiteur.
    Pour donner un exemple qui colle bien : la ligne de commande d'une application windows (WinMain).
    Chaque argument est séparé par un espace, mais on peut mettre un argument entre guillemet pour permettre les espaces au sein de celui. De plus, pour permettre de mettre un guillemet dans un argument on doit pouvoir le préfixer un backslash.
    Voilà, c'est ce genre de split que je cherche à faire, et n'étant pas spécialement doué avec la STL je n'arrive pas à trouver d'algo qui ne soit pas une usine à gaz.

    Vous auriez des pistes ? De préférence en pure STL, mais bon, s'il faut un coup de boost ça m'ira aussi.
    Merci du coup de main

  2. #2
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Par défaut
    A mon avis, le plus simple :
    - oublie le split (au sens découpage d'une chaine en fonction d'un caractère)
    - tu fais une lecture séquentielle (tu lis le premier mot, tu le cherche dans ta liste de mots clés, tu regardes les paramètres qu'il prend, tu recommences)

    Sinon, tu laisses Boost.Program_options faire son boulot...

  3. #3
    Membre Expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Par défaut
    Oui ou alors tu peux utiliser boost::regex aussi si tu tiens à écrire le split toi même. Les regex sont dans le standard C++11 si tu l'utilises.

  4. #4
    Membre émérite Avatar de ctxnop
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2007
    Messages
    858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2007
    Messages : 858
    Par défaut
    Salut, merci de la réponse
    cependant, ça ne correspond pas vraiment à la demande.
    Comme je l'ai indiqué, le parse d'une ligne de commande n'est qu'un exemple.
    Ce que je souhaite c'est bel et bien splitter la chaine, mais je ne veux pas un simple délimiteur. Je veux pouvoir utiliser un/des caractères pour grouper des morceaux de la chaine au sein desquels le délimiteur n'a pas d'effet.

    En fait, j'y arrive très bien à faire tout ça, simplement je me demande si il n'y aurait pas plus simple/propre/efficace en utilisant la STL.
    Mon code actuel consiste à parcourir la chaine, caractère par caractère, en utilisant une boucle 'for' et les iterateurs. Ensuite, avec quelques switchs imbriqués je décide de mettre le caractère en fin d'une autre string, d'ajouter la string ainsi construite au vecteur, etc...

    Je vous aurais bien coller le code ici mais je ne l'ai pas avec moi, il est resté sur l'ordi du boulot...

  5. #5
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Par défaut
    Alors effectivement, c'est soit des regex, soit utiliser les DSL (avec boost.spirit par exemple)

  6. #6
    Membre Expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Par défaut
    Ce n'est peut être pas une bonne solution, mais si tu utilises Boost.Tokenizer (http://www.boost.org/doc/libs/1_47_0.../tokenizer.htm ) tu as juste à fournir un fonctor intelligent comme paramettre TokenizerFunc et tu auras un "split intelligent".

    Cela étant dit, perso je préfère un split qui split plutot qu'un split qui fait des trucs de ninja dans mon dos...

  7. #7
    Membre émérite Avatar de ctxnop
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2007
    Messages
    858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2007
    Messages : 858
    Par défaut
    Mouais, les regex j'aime beaucoup mais je trouve que c'est sortir l'artillerie pour pas grand chose. C'est sur que ca me fera un code beaucoup plus petit que celui que j'ai actuellement, mais je doute qu'il soit vraiment efficace.

    Les DSL je ne connais absolument pas, vous auriez un exemple ?

    Sinon, j'ai re-codé ma fonction histoire de pouvoir vous la montrer :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
     
    #include <vector>
    #include <string>
     
    #define TSTRING std::basic_string<T, std::char_traits<T>, std::allocator<T>>
    #define SSPLIT_STATE_NORMAL		0
    #define SSPLIT_STATE_GROUP		1
    #define SSPLIT_STATE_ESCAPE		2
     
    template <class T>
    std::vector<TSTRING> smartSplit(const TSTRING& str, const T delim, const T gStart, const T gStop, const T escape)
    {
    	std::vector<TSTRING> v;
    	TSTRING a;
    	TSTRING::const_iterator i = str.begin();
    	TSTRING::const_iterator e = str.end();
    	int state = SSPLIT_STATE_NORMAL;
    	for(; i != e; ++i)
    	{
    		switch(state)
    		{
    		case SSPLIT_STATE_NORMAL:
    			if (*i == delim)
    			{
    				if(a.size())
    				{
    					v.push_back(a);
    					a.clear();
    				}
    			}
    			else if (*i == gStart)
    			{
    				state = SSPLIT_STATE_GROUP;
    			}
    			else if (*i == escape)
    			{
    				state = SSPLIT_STATE_ESCAPE;
    			}
    			else
    			{
    				a.push_back(*i);
    			}
    			break;
    		case SSPLIT_STATE_GROUP:
    			if(*i == escape)
    			{
    				state += SSPLIT_STATE_ESCAPE;
    			}
    			else if(*i == gStop)
    			{
    				if(a.size())
    				{
    					v.push_back(a);
    					a.clear();
    				}
    				state = SSPLIT_STATE_NORMAL;
    			}
    			else
    			{
    				a.push_back(*i);
    				break;
    			}
    			break;
    		case SSPLIT_STATE_ESCAPE:
    		case SSPLIT_STATE_ESCAPE | SSPLIT_STATE_GROUP:
    			a.push_back(*i);
    			state -= SSPLIT_STATE_ESCAPE;
    			break;
    		}
    	}
    	if(a.size()) v.push_back(a);
    	return v;
    }
    Vous en pensez quoi ?

  8. #8
    Membre Expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Par défaut
    Citation Envoyé par ctxnop Voir le message
    Mouais, les regex j'aime beaucoup mais je trouve que c'est sortir l'artillerie pour pas grand chose. C'est sur que ca me fera un code beaucoup plus petit que celui que j'ai actuellement, mais je doute qu'il soit vraiment efficace.

    Les DSL je ne connais absolument pas, vous auriez un exemple ?

    Sinon, j'ai re-codé ma fonction histoire de pouvoir vous la montrer :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
     
    #include <vector>
    #include <string>
     
    #define TSTRING std::basic_string<T, std::char_traits<T>, std::allocator<T>>
    #define SSPLIT_STATE_NORMAL		0
    #define SSPLIT_STATE_GROUP		1
    #define SSPLIT_STATE_ESCAPE		2
     
    template <class T>
    std::vector<TSTRING> smartSplit(const TSTRING& str, const T delim, const T gStart, const T gStop, const T escape)
    {
    	std::vector<TSTRING> v;
    	TSTRING a;
    	TSTRING::const_iterator i = str.begin();
    	TSTRING::const_iterator e = str.end();
    	int state = SSPLIT_STATE_NORMAL;
    	for(; i != e; ++i)
    	{
    		switch(state)
    		{
    		case SSPLIT_STATE_NORMAL:
    			if (*i == delim)
    			{
    				if(a.size())
    				{
    					v.push_back(a);
    					a.clear();
    				}
    			}
    			else if (*i == gStart)
    			{
    				state = SSPLIT_STATE_GROUP;
    			}
    			else if (*i == escape)
    			{
    				state = SSPLIT_STATE_ESCAPE;
    			}
    			else
    			{
    				a.push_back(*i);
    			}
    			break;
    		case SSPLIT_STATE_GROUP:
    			if(*i == escape)
    			{
    				state += SSPLIT_STATE_ESCAPE;
    			}
    			else if(*i == gStop)
    			{
    				if(a.size())
    				{
    					v.push_back(a);
    					a.clear();
    				}
    				state = SSPLIT_STATE_NORMAL;
    			}
    			else
    			{
    				a.push_back(*i);
    				break;
    			}
    			break;
    		case SSPLIT_STATE_ESCAPE:
    		case SSPLIT_STATE_ESCAPE | SSPLIT_STATE_GROUP:
    			a.push_back(*i);
    			state -= SSPLIT_STATE_ESCAPE;
    			break;
    		}
    	}
    	if(a.size()) v.push_back(a);
    	return v;
    }
    Vous en pensez quoi ?
    Que ça ressemble furieusement à un AFD, et donc à une regex compilée (sans le coté "facile à mettre en oeuvre, testé par d'autres et validé".

    Ceci dit, je te rejoins lorsque tu parles d'artillerie lourde. La première fois que j'ai vu ça (pseudo-emphase de ma part):

    Citation Envoyé par standard C++11, section 28.5.1
    namespace std {
    namespace regex_constan ts {
    typedef T1 syntax_option_type;
    static constexpr syntax_option_type icase = unspecified ;
    static constexpr syntax_option_type nosubs = unspecified ;
    static constexpr syntax_option_type optimize = unspecified ;
    static constexpr syntax_option_type collate = unspecified ;

    static constexpr syntax_option_type ECMAScript = unspecified ;
    static constexpr syntax_option_type basic = unspecified ;
    static constexpr syntax_option_type extended = unspecified ;
    static constexpr syntax_option_type awk = unspecified ;
    static constexpr syntax_option_type grep = unspecified ;
    static constexpr syntax_option_type egrep = unspecified ;
    }
    }
    Je me suis dit : "tiens, on dirait qu'ils ont décidé de ne pas supporter plus de 6 types différents d'expressions régulières".

    Comme si une seule, deux à la rigueur, n'étaient pas suffisant.

    (après, on s'étonne que la libstdc++ de GNU soit en retard à ce niveau précis : vous voyez vous profiler les dépendances énormes nécessaires pour implémenter tout ça ?)
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

+ Répondre à la discussion
Cette discussion est résolue.

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo