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 :

Lecture dans un fichier et conversion avec std::istringstream


Sujet :

C++

  1. #1
    Membre du Club
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2013
    Messages
    32
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Janvier 2013
    Messages : 32
    Points : 47
    Points
    47
    Par défaut Lecture dans un fichier et conversion avec std::istringstream
    Bonjour,

    J'essaie de lire le contenu d'un fichier texte dont le contenu ressemble à ceci :
    Pour chaque ligne je voudrais récupérer les deux valeurs dans deux variables de type int.
    J'y parviens en utilisant ce code :
    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
    #include <iostream>
    #include <fstream>
    #include <sstream>
    using namespace std;
    int main(int argc, char **argv) {
        string nomFichier = "test1.txt";
        ifstream fichier(nomFichier.c_str(), ios::in);
        string ligne;
        int first, second; 
     
        while(getline(fichier, ligne)) {
            cout << ligne << "\t=>\t";
            istringstream ss(ligne);
            ss >> first >> second;
            cout << first << "\t" << second << endl;
            ss.str().clear();
        }
     
        fichier.close();
        return 0;
    }
    Le seul "problème" est que je déclare un istringstream à chaque itération, ce qui ne me semble pas très propre ni optimisé.
    Pouvez-vous m'indiquer comment modifier ce code pour ne créer un qu'un seul istringstream et le réinitialiser avec la nouvelle ligne à chaque passage dans la boucle ?

    Je précise que je suis débutant en C++ et que j'ai trouvé un message, ici, qui semble répondre à ma question, mais je n'ai pas réussi à mettre en oeuvre la solution indiquée.

    Merci d'avance

  2. #2
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    745
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 745
    Points : 3 660
    Points
    3 660
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    istringstream ss;
    while(getline(fichier, ligne)) {
        cout << ligne << "\t=>\t";
        ss.str(ligne);
        if (!(ss >> first >> second)) {
            //erreur
        }
        cout << first << "\t" << second << endl;
    }
    Mais sinon, tu peux tous lire en une traite. Les flux considèrent les espaces, sauts de ligne et tabulations comme un seul caractère d'espacement.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    while(fichier >> first >> second) {
        cout << first << "\t" << second << endl;
    }

  3. #3
    Membre du Club
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2013
    Messages
    32
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Janvier 2013
    Messages : 32
    Points : 47
    Points
    47
    Par défaut
    En appliquant ta première proposition je ne parviens pas tout à fait à faire ce que je veux. Avec ce code ce sont toujours les données de la première ligne qui sont affichées.
    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
    #include <iostream>
    #include <fstream>
    #include <sstream>
    using namespace std;
    int main(int argc, char **argv) {
        string nomFichier = "test1.txt";
        ifstream fichier(nomFichier.c_str(), ios::in);
        string ligne;
        int first, second; 
     
        istringstream ss;
        while(getline(fichier, ligne)) {
            cout << ligne << "\t=>\t";
            ss.str(ligne);
            if (!(ss >> first >> second)) {/*erreur*/}
            cout << first << "\t" << second << endl;
            ss.str().clear();
        }        
        fichier.close();
        return 0;
    }
    La sortie donne ceci, que je mette ou pas la ligne 17 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    1 45    =>      1       45
    21 2    =>      1       45
    3 7     =>      1       45
    En revanche la deuxième solution fonctionne très bien. Par contre je ne suis pas certain de bien comprendre pourquoi
    J'ai un peu de mal à voir dans quel ordre se fait l'évaluation de la ligne while(fichier >> first >> second), pourquoi les lignes sont bien lues une à une et pas autrement, etc.
    Si tu peux me donner quelques explications je suis preneur.

    Merci pour tes réponses.

  4. #4
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    745
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 745
    Points : 3 660
    Points
    3 660
    Par défaut
    Oups, pour le premier exemple j'ai oublié de mettre ss.clear(); avant le if. Lorsque les 2 nombre sont lus, le flux passe éventuellement en oef s'il n'y a plus rien sur la ligne. Il faut donc le remettre dans un état valide (ios::clear).
    Le clear() de ss.str().clear(); fait partit de std::string et ne fait strictement rien ici. str() retourne un std::string et clear() la vide...

    Citation Envoyé par Eldergrim Voir le message
    En revanche la deuxième solution fonctionne très bien. Par contre je ne suis pas certain de bien comprendre pourquoi
    J'ai un peu de mal à voir dans quel ordre se fait l'évaluation de la ligne while(fichier >> first >> second), pourquoi les lignes sont bien lues une à une et pas autrement, etc.
    Si tu peux me donner quelques explications je suis preneur.
    L’évaluation se fait dans le sens de la lecture first puis second puis on recommence.
    Que ça lise ligne pas ligne n'est qu'une conséquence du format utilisé. Les nombres pourraient être tous sur une ligne ou un par ligne le résultat sera le même.

    Quand une type scalaire (char fait exception) est lu, le flux va ignorer tous les espaces blancs. Ces caractères sont grosso modo déterminés par isspace.
    Ensuite, par exemple pour un int, il va récupérer tous les caractères qui suivent et transformer ça en entier.
    Si une erreur survient pendant la lecture comme un caractère invalide (comprendre différent d'un chiffre) ou la fin du fichier, alors le flux change d'état et la boucle s'arrête.
    Faire if(fichier >> variable); et l'équivalent de fichier >> variable; if (fichier.good());.

  5. #5
    Membre du Club
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2013
    Messages
    32
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Janvier 2013
    Messages : 32
    Points : 47
    Points
    47
    Par défaut
    La première solution fonctionne effectivement mieux avec le ss.clear().

    Pour la deuxième méthode, je vais faire quelques tests pour mieux comprendre le fonctionnement. Je n'ai pas l'habitude d'utiliser des flux, et encore moins en C++. Il faut que je pratique !

    Merci pour tes explications.

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

Discussions similaires

  1. Réponses: 1
    Dernier message: 16/03/2010, 09h58
  2. Lecture dans un fichier excel avec C#
    Par randriamanana dans le forum ASP.NET
    Réponses: 3
    Dernier message: 24/10/2007, 11h20
  3. Lecture dans un fichier avec lseek
    Par Maria1505 dans le forum Linux
    Réponses: 8
    Dernier message: 24/02/2007, 12h29
  4. Réponses: 20
    Dernier message: 25/09/2005, 15h07
  5. Réponses: 12
    Dernier message: 14/06/2004, 13h06

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