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

SL & STL C++ Discussion :

skipws marche pas quand il n'y a que des espaces !


Sujet :

SL & STL C++

  1. #1
    Nouveau membre du Club
    Inscrit en
    Septembre 2005
    Messages
    33
    Détails du profil
    Informations forums :
    Inscription : Septembre 2005
    Messages : 33
    Points : 34
    Points
    34
    Par défaut skipws marche pas quand il n'y a que des espaces !
    Bonjour,

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    istringstream record ("  ");
    string s;
    record >> skipws >> s;
    Résultat: s n'est pas vide (1 espace, comme record). Je pensais que le manipulateur skipws était sensé faire sauter les espaces à l'opérateur d'extraction !
    Cela marche si record = " 4" par exemple, on aboutit à s = "4". Mais pas quand record est complètement fait d'espaces.

    J'ai raté qqe chose ou c'est un bug de Cygwin (lidstd++ plutôt..).

    Merci.

  2. #2
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    Avec Express VC++ et gcc, j'ai bien une chaine vide :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    #include <iostream>
    #include <string>
    #include <sstream>
     
    using namespace std;
    int main(int, char)
    {
       istringstream record ("  ");
       string s;
       record >> skipws >> s;
       std::cout<<s.length()<<std::endl;
       return 0;
    }
    J'ai bien 0!

  3. #3
    Nouveau membre du Club
    Inscrit en
    Septembre 2005
    Messages
    33
    Détails du profil
    Informations forums :
    Inscription : Septembre 2005
    Messages : 33
    Points : 34
    Points
    34
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    Salut,
    Avec Express VC++ et gcc, j'ai bien une chaine vide
    bah moi aussi avec ton programme !
    En fait ce que je fait c'est ça (parsing d'un fichier au format très simple) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    ifstream mapFile ( fname, ifstream::in ); // Read text
    istringstream record;
    while( ! mapFile.eof() ) { // Leaves \n in input
        try { 
    	string s;
    	getline( mapFile, s ); // \n is discarded
    	record.clear();
    	record.str(s); record >> skipws >> s; 
    	cout << "|" << s << "|" <<endl;
    	record.seekg( 0, ios::beg );
    	...
       catch(ifstream::failure e) {...}
    }
    Et avec ça, si j'ai une ligne avec seulement des espaces, j'ai des choses comme ça en output : !
    Pär contre en ajoutant un s.clear() entre record.str(s) et record >> skipws >> s :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    record.str(s); s.clear(); record >> skipws >> s;
    là ça marche !
    J'ai constaté avec mes tests qu'il fallait des record.clear() et record.seekg en début de boucle sans quoi du débris s'accumule dans record, mais pour s, je ne comprends pas pourquoi il y a besoin d'un clear(). Son scope est dans le try{ }, donc on a un s tout frais en début de boucle normalement !

  4. #4
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 379
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 379
    Points : 41 573
    Points
    41 573
    Par défaut
    J'ai un horrible pressentiment.
    Vérifie que " 4" marche toujours avant de crier victoire...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  5. #5
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    A un moment donnée, j'avais eu quelque soucis avec des stringstream et, de mémoire, on m'avait conseillé de ne pas les réutiliser. Donc en modifiant ton code comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    ifstream mapFile ( fname, ifstream::in ); // Read text
    while( ! mapFile.eof() ) { // Leaves \n in input
        try { 
    	string s;
    	getline( mapFile, s ); // \n is discarded
            istringstream record(s);
    	record.str(s); record >> skipws >> s; 
    	cout << "|" << s << "|" <<endl;
    	record.seekg( 0, ios::beg );
    	...
       catch(ifstream::failure e) {...}
    }
    Qu'en est-il?

  6. #6
    Nouveau membre du Club
    Inscrit en
    Septembre 2005
    Messages
    33
    Détails du profil
    Informations forums :
    Inscription : Septembre 2005
    Messages : 33
    Points : 34
    Points
    34
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    J'ai un horrible pressentiment.
    Vérifie que " 4" marche toujours avant de crier victoire...
    Je sais à quoi tu penses
    L'analyse de l'enregistrement en cours se fait avec le contenu de record et non de s. s sert seulement pour tester si la ligne est vide (vide ou ne contenant que des blancs) - s.empty().
    Maintenant que je fais des getline( record, s, ' ' ); (dans une autre fonction - parseRecord()), je vois en effet que getline se croute sur recod.eof pour une ligne comme " 4", et s reste vide..
    Das suggestions pour découper " 4 152 198365672" selon les espaces (sans Boost ou classe Tokenizer méchante! )


    @3DArchi : qu'est ce que tu crois ? que les clear() et les seekg() m'amusent ?!
    bien sûr que j'aurais préféré un record tout frais en début de boucle (comme pour s). Mais yé pé pas ! (tu veux le n° de mon boss ? )

  7. #7
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    La réponse est subtile et se trouve ici.
    Le principe: toute surcharge de l'opérateur >> (ou << pour l'output) doit passer par std::sentry. Or std::sentry va, entre autre, nettoyer les espaces du flux si skipws est positionné. Donc lorsque tu fais record >> s;, il commence par nettoyer les espaces, aboutit à un flux vide qu'il positionne en erreur. Donc s n'est même pas réinitialisé et reste avec sa valeur précédente! La seule solution que je vois consisterait à tester l'erreur sur la lecture de s et positionner celle-ci à vide en ce cas. C'est assez bancale, pour ne pas dire plus :
    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
    ifstream mapFile ( fname, ifstream::in ); // Read text
    while( ! mapFile.eof() ) { // Leaves \n in input
        try { 
    	string s;
    	getline( mapFile, s ); // \n is discarded
            istringstream record(s);
    	record.str(s); 
    	record >> skipws;
    	if((record >> s).fail()){
    		s.clear();
    	} 
    	cout << "|" << s << "|" <<endl;
    	record.seekg( 0, ios::beg );
    	...
       catch(ifstream::failure e) {...}
    }

  8. #8
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    Salut,
    La réponse est subtile et se trouve ici.
    Formulé autrement, tu demandes d'avancer jusqu'à trouver un caractère que ne soit pas une espace. Il arrive en fin de flux sans en trouver, ce dernier passe donc en erreur, et toute opération dessus devient une no-op.

    Citation Envoyé par 3DArchi Voir le message
    La seule solution que je vois consisterait à tester l'erreur sur la lecture de s et positionner celle-ci à vide en ce cas.
    Je n'ai pas lu la totalité du code, mais a priori, le plus simple me semble encore d'utiliser une première variable pour lire l'ensemble de la ligne, et une seconde pour en extraire l'information.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    	string s, line;
    	getline( mapFile, line ); // \n is discarded
    	record.clear();
    	record.str(line); 
    	record >> skipws >> s;
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  9. #9
    Nouveau membre du Club
    Inscrit en
    Septembre 2005
    Messages
    33
    Détails du profil
    Informations forums :
    Inscription : Septembre 2005
    Messages : 33
    Points : 34
    Points
    34
    Par défaut Résolu
    Citation Envoyé par 3DArchi Voir le message
    Salut,
    La réponse est subtile et se trouve ici.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    	record >> skipws;
    	if((record >> s).fail()){
    		s.clear();
    	} 
    
    Ce fil est résolu !
    @JolyLoic; Je préfère faire s.clear() systématiquement, c'est plus paresseux et me fait l'économie d'une variable.

    Merci à tous les contributeurs et au plaisir !

  10. #10
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 860
    Points
    11 860
    Par défaut
    Si je peux me permettre, n'oublie pas Boost si les choses se compliquent. Ca te permettra de garder la main sur ta conception et sur la modularité tout en réalisant pleinement le parsing que tu souhaites faire (je pense à Tokenizer, Regexp et Spirit).

  11. #11
    Nouveau membre du Club
    Inscrit en
    Septembre 2005
    Messages
    33
    Détails du profil
    Informations forums :
    Inscription : Septembre 2005
    Messages : 33
    Points : 34
    Points
    34
    Par défaut
    Citation Envoyé par Alp Voir le message
    Si je peux me permettre, n'oublie pas Boost si les choses se compliquent.
    Bien sûr que j'y pense, mais j'essaie de coller au standard autant que faire se peut, et je peux m'en tirer dans ce cas sans trop de dégâts. Ma fonction de parsing reste sous contôle (une 40aine de ligne - cf. ci-bas).
    En même temps, un standard qui ne supporte pas les regexp en est-il un ?!

    Autant je considère les regexp comme le point d'échec d'un langage (le point le plus éloigné du langage naturel - ici l'anglais - vers lequel doit tendre au maximum tout langage de programmation, le langage de programmation ultime étant de pouvoir causer à un ordi en bon anglais/français/allemand/...), autant il y a des situations où une regexp fait gagner tellement de lignes de code que ça justifie largement le cout en termes de "code-mystification"..

    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
    // Record format : <iFrom> [iTo] <ckSum>
    bool parseRecord( istringstream& record, unsigned long &iFrom, unsigned long &iTo, string &ckSum ) {
     
       istringstream sparser;
       string s;
     
       iFrom = 0; iTo = 0; ckSum.clear();
     
       // format : <1> [152] <198365673>
       record >> skipws >> s; sparser.str(s);
       //cout << "1st field: |" << s << "|\n";
       if( ! isStrDigit(s) ) {
          cerr << "\nparseRecord: Error: malformed record: first word not a number.\n";
          return false;
       } else sparser >> iFrom; //sparser.clear();
       if( iFrom == 0 ) {
          cerr << "\nparseRecord: Error in record: slice start index can not be 0!\n";
          return false;
       }
     
       s.clear(); sparser.clear();
       record >> skipws >> s; sparser.str(s);
       if( s.empty() ) {
          cerr << "\nparseRecord: Error: malformed record: checksum missing!\n";
          return false;
       }
     
       record >> skipws >> ckSum;
       if ( ckSum.empty() ) ckSum = s; // if no, then 2nd one was the checksum
       else {                          // otherwise it's iTo. ckSum is loaded, now take care of iTo :
          if( isStrDigit(s) ) { 
             sparser >> iTo;
             if( iTo == 0 ) {
                cerr << "\nparseRecord: Error in record: slice end index can not be 0!\n";
                return false;
             }
          }
          else {
             cerr << "\nparseRecord: Error: malformed record: second word not a number!\n";
             return false;
          }
       }
     
       return true;
    }
    C'est vrai que pour un format simple à parser, si ma fonctioin commençait à tendre vers la 100aine de lignes, je me poserais sérieusement la question de Booster ou pas mon code !

  12. #12
    Rédacteur

    Avatar de ram-0000
    Homme Profil pro
    Consultant en sécurité
    Inscrit en
    Mai 2007
    Messages
    11 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultant en sécurité
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2007
    Messages : 11 517
    Points : 50 367
    Points
    50 367
    Par défaut
    Vu que tu parles de Regex et de boost, va voir ici, c'est un tuto que je viens juste de finir d'écrire
    Raymond
    Vous souhaitez participer à la rubrique Réseaux ? Contactez-moi

    Cafuro Cafuro est un outil SNMP dont le but est d'aider les administrateurs système et réseau à configurer leurs équipements SNMP réseau.
    e-verbe Un logiciel de conjugaison des verbes de la langue française.

    Ma page personnelle sur DVP
    .

  13. #13
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 860
    Points
    11 860
    Par défaut
    Les Regex sont dans le technical report 1 il me semble, qui est fourni avec les dernières versions de g++ et VC++, au moins.
    Dans tous les cas, le prochain standard contiendra bien plus de choses

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

Discussions similaires

  1. [SP-2010] event receiver qui ne marche pas quand il est couplé avec un content type
    Par cekamb72 dans le forum SharePoint
    Réponses: 6
    Dernier message: 29/08/2011, 18h53
  2. [AC-2003] Requête qui ne marche pas quand je l'utilise en VBA ?
    Par [ZiP] dans le forum Requêtes et SQL.
    Réponses: 1
    Dernier message: 31/03/2010, 10h28
  3. Projet Web qui ne marche pas quand déployé avec un WAR
    Par aeMAETH dans le forum Eclipse Java
    Réponses: 0
    Dernier message: 22/09/2009, 03h09
  4. [script.aculo.us] Effect.Appear() ne marche pas quand je mets le style dans un fichier .css
    Par ilalaina dans le forum Bibliothèques & Frameworks
    Réponses: 2
    Dernier message: 14/07/2009, 09h07
  5. new Option : ne marche pas quand le code est en alpha ???
    Par Leoxp dans le forum Général JavaScript
    Réponses: 4
    Dernier message: 19/12/2005, 15h23

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