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 :

équivalent formatage sscanf


Sujet :

C++

  1. #1
    Membre éclairé Avatar de befalimpertinent
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    561
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Gironde (Aquitaine)

    Informations forums :
    Inscription : Avril 2007
    Messages : 561
    Points : 833
    Points
    833
    Par défaut équivalent formatage sscanf

    Je cherche en vain l'équivalent c++ de :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    while(fgets(line,sizeof(line),fich))
      {
        int p[3];
        if(sscanf(line,"v %f %f %f",&p[0],&p[1],&p[2]) == 3)
        {
           /*create new point*/
        }
        int i,j,k;
        if(sscanf(line,"f %d %d %d",&i,&j,&k) == 3)
        {
          /*create face (i,j,k)*/
        }
      }
    Qui sert à parser un fichier .obj.

    J'ai consulté la pour lire un fichier ligne par ligne donc aucun problème à ce niveau là. Mais après je ne trouve pas d'outil aussi puissant que sscanf qui en une seule ligne rempli mon tableau int p[3] si la ligne du fichier commence par un v et est suivi de 3 entier.

    The question is : y a t'il un équivalent aussi puissant que sscanf en C++ ? Parceque istringstream c'est bien gentil mais je dois faire tout le travail de validation en amont.

    Merci d'avance
    Linux > *

  2. #2
    Membre chevronné
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Points : 2 107
    Points
    2 107
    Par défaut
    Oui enfin getline et les istringstream sont beaucoup plus générique que sscanf quand même. Là tu as beaucoup de connaissances a priori sur ton fichier.

    Dans ce cas, ce code marche aussi...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    std::ifstream file("test.txt");
    std::string line;
    while ( std::getline( file, line ) )
    {
        int p[3];
        file >> &p[0] >> &p[1] >> &p[2];
    }
    Et je lis tout en une ligne aussi...

  3. #3
    Membre éclairé Avatar de befalimpertinent
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    561
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Gironde (Aquitaine)

    Informations forums :
    Inscription : Avril 2007
    Messages : 561
    Points : 833
    Points
    833
    Par défaut
    Sauf que tu oublis de vérifier si la ligne commence par v ou f avant de stocker des données et là ça te fait une ligne de plus.
    Et comment s'assurer que la ligne contient bien 3 entier (float en fait je me suis planter en recopiant le code ).

    s'assure tout seul que je récupère bien les trois valeurs attendues
    Linux > *

  4. #4
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    Citation Envoyé par poukill Voir le message
    Oui enfin getline et les istringstream sont beaucoup plus générique que sscanf quand même. Là tu as beaucoup de connaissances a priori sur ton fichier.

    Dans ce cas, ce code marche aussi...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    std::ifstream file("test.txt");
    std::string line;
    while ( std::getline( file, line ) )
    {
        int p[3];
        file >> &p[0] >> &p[1] >> &p[2];
    }
    Et je lis tout en une ligne aussi...
    Ah non c'est pas pareil....
    Je croit que boost as un truc comme ca

  5. #5
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    Citation Envoyé par befalimpertinent Voir le message
    Sauf que tu oublis de vérifier si la ligne commence par v ou f avant de stocker des données et là ça te fait une ligne de plus.
    Et comment s'assurer que la ligne contient bien 3 entier (float en fait je me suis planter en recopiant le code ).

    s'assure tout seul que je récupère bien les trois valeurs attendues
    tout comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    nbsommet = sscanf(line,"f %d %d %d %d ",&i,&j,&k,&l) 
    if(nbsommet ==3)
        {
          /*create triangle(i,j,k)*/
        }
    if(nbsommet ==4)
        {
          /*create quadrangle(i,j,k)*/
        }

  6. #6
    Membre éclairé Avatar de befalimpertinent
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    561
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Gironde (Aquitaine)

    Informations forums :
    Inscription : Avril 2007
    Messages : 561
    Points : 833
    Points
    833
    Par défaut
    Bien sur!
    Quand je dis "en une seule ligne" je veux dire en réalité "de la manière la plus simple et la plus élégante possible".
    Linux > *

  7. #7
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    Citation Envoyé par befalimpertinent Voir le message
    Bien sur!
    Quand je dis "en une seule ligne" je veux dire en réalité "de la manière la plus simple et la plus élégante possible".
    Personnellement, je mélange parfois les deux.
    Je lit avec les flux (ligne par ligne souvent) et quand je doit traiter une string, j'utilise sscanf


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    std::string(ligne);
    f.getligne(ligne);
    sscanf(ligne.c_str(), ...);

  8. #8
    Membre éclairé Avatar de befalimpertinent
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    561
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Gironde (Aquitaine)

    Informations forums :
    Inscription : Avril 2007
    Messages : 561
    Points : 833
    Points
    833
    Par défaut
    J'en suis aussi arriver à cette conclusion.
    Mais en tant qu'intégriste du C++ je préfèrerai éviter ce mélange
    Linux > *

  9. #9
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    L'un dans l'autre, tu pourrais envisager d'utiliser une structure pour tes points et de déclarer un constructeur prenant une référence sur std::istream en paramètre.
    Ta classe deviendrait quelque chose du genre de
    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
    class Point
    {
        public:
            Point()
            {
                coord[0]=0;
                coord[1]=0;
                coord[2]=0;
            }
            Point(float x, float y, float z)
            {
                coord[0]=x;
                coord[1]=y;
                coord[2]=z;
            }
            Point(std::istream& ss)
            {
                ss>>coord[0]>>coord[1]>>coord[2];
            }
            void Print()
            {
                std::cout<< "x : "<<coord[0]<<" y: "<<coord[1]<<" z: "<<coord[2]
                         <<std::endl;
            }
            float* GetCoord(){return coord;}
        private:
            float coord[3];
    };
    et l'utilisation se ferait sous forme de
    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
     
    void ReadObjFile(const std::string& filename)
    {
        ifstream ff(filename.c_str());
        vector<Point> tabpoint; /* ici, c'est juste pour récupérer les points ;)*/
        std::string read;
        while(std::getline(ff,read))
        {
            std::stringstream ss;
            ss<<read;
            char c;
            ss>>c;
            switch(c)
            {
                case 'v':/* attention, il existe aussi vn ??? */
                    tabpoint.push_back(Point(ss));
                    /* pourrait etre, de manière plus classique
                    Point p(ss);
                    tabpoint.push_back(p); */
                    /* l'affichage pour la forme */
                   std::cout<<"point cree"<<std::endl;
                    break;
                case 'f':
                    /* gestion pour "f"
                    break;
              /*les autres possibilités*/
                 default: 
                    std::cout<<"code inconnu"<<std::endl;
            }
        }
        /* la vérif pour la forme ;) */
        std::cout<<tabpoint.size()<<" points trouves "<<std::endl;
        for(size_t i=0;i<tabpoint.size();i++)
            tabpoint[i].Print();
    }
    [EDIT]Evidemment, ce qui est valable pour un "point" l'est aussi pour tout le reste

    [EDIT 2]Pour t'assurer que tu récupères à chaque fois le nombre correct d'élément sur tes structures, tu peux modifier le constructeur sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    Point::Point(std::istream& ss)
    {
        if(!(ss>>coord[0]>>coord[1]>>coord[2]))
            throw std::runtime_error("erreur lecture");/* ou une exception "perso"*/
    }
    et "catcher" l'exception dans la fonction de lecture
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  10. #10
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    comment ferait avec les istream dans le cas ou dans le fichier obj

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    f 1 2 3                     //triangle
    f 4 8 9 10                //quadragle
    f 1/2 5/9 9/2            //triangle avec indice sur les sommet et les normales
    f 5 9 6 3 8 9 7 1       //face a x sommet

  11. #11
    Membre éclairé Avatar de befalimpertinent
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    561
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Gironde (Aquitaine)

    Informations forums :
    Inscription : Avril 2007
    Messages : 561
    Points : 833
    Points
    833
    Par défaut
    J'avais pas penser au istream en paramètre de constructeur.
    ça me parait la solution la plut élégante et la plus "C++ look like". Je prend



    @Mongaulois

    Mon fichier est au format obj wavefront et je ne sais pas si ce genre de syntaxe est autorisée mais la question est intéressante tout de même.
    Linux > *

  12. #12
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    Citation Envoyé par befalimpertinent Voir le message
    Mon fichier est au format obj wavefront et je ne sais pas si ce genre de syntaxe est autorisée mais la question est intéressante tout de même.
    Oui sans problème.
    voici un lien sur le format obj :
    http://people.scs.fsu.edu/~burkardt/txt/obj_format.txt

  13. #13
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par Mongaulois Voir le message
    comment ferait avec les istream dans le cas ou dans le fichier obj

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    f 1 2 3                     //triangle
    f 4 8 9 10                //quadragle
    f 1/2 5/9 9/2            //triangle avec indice sur les sommet et les normales
    f 5 9 6 3 8 9 7 1       //face a x sommet
    Ben, tu partirais sur des structures du genre de
    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
     
    class FormInterface
    {
        public:
            FormInterface(){}
            virtual ~FormInterface(){}
            /* déclaration des fonctions "qui vont bien" en virtuelles pure */
    }
    class Form:public FormInterface
    {
        public:
            Form(istream& ss)
           {
                /* erreur si on n'a pas au moins 3 points */
                if(!(ss>>point[0]>>point[1]>>point[2]))
                    throw std::runtime_error("erreur lecture");
                isquadri=(ss>>point[3]);
            }
            /* reféfinition des fonctions virtuelles pures */
        private:
            int points[4];
            bool isquadri;
    };
    class NormalizedForm:public FormInterface
    {
        public:
            NormalizedForm(istream& ss)
            {
                 char c[4];
                /* erreur si on n'a pas au moins 3 points et trois normales */
                if(!(ss>>point[0]>>c[0]>>norm[0]
                       >>point[1]>>c[1]>>norm[1]
                       >>point[2]>>c[2]>>norm[2]))
                    throw std::runtime_error("erreur lecture");
                isquadri=(ss>>point[4]>>c[3]>>norm[3]);
            }
            /* reféfinition des fonctions virtuelles pures */
        private:
            int points[4];
            bool isquadri;
            int norm[4];
    };
    class MultiSommet:public FormInterface
    {
        public:
            MultiSommet(stream& ss, size_t _nb):nb(_nb)
            {
                 sommets=new int[nb]
                 for(size_t i=0;i<nb;i++)
                     if(!(ss>>sommets[i]))
                         throw runtime_error("erreur de lecture")
            }
            /* reféfinition des fonctions virtuelles pures */
        private:
            size_t nb;
            int *sommets;
    };
    Je précise que je n'ai pas pris le temps de réfléchir à toutes les implications... on pourrait, par exemple, ne prévoir qu'une forme "multi sommets", et pas de Form

    Cela sous entend, qu'ici, la fonction qui s'occupera d'appeler le constructeur devra, aussi, prendre en charge la vérification du genre d'objet à créer
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  14. #14
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    ...
    le problème est que l'on as aucune connaissance "en théorie" comment sera écrite cette ligne à l'instant de la lecture. toute ces formes sont correctes et peuvent être mélangé.
    Pour moi les flux sont trés bof pour faire du traitement complex sur des string. En fin j'ai jamais trouvé de super méthode simple avec les flux.
    Pour des truc basique c'est super.

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

Discussions similaires

  1. formatage dans un sscanf
    Par straasha dans le forum C
    Réponses: 11
    Dernier message: 30/05/2011, 11h44
  2. équivalent de sscanf en c++
    Par franc82 dans le forum C++
    Réponses: 1
    Dernier message: 08/11/2006, 09h50
  3. Formatage d'une chaine pour sscanf
    Par Pragmateek dans le forum C
    Réponses: 6
    Dernier message: 30/04/2006, 00h11
  4. pb formatage document XML généré par un dom tree
    Par lionel69 dans le forum APIs
    Réponses: 11
    Dernier message: 17/10/2002, 09h53
  5. Équivalent du #IFDEF
    Par agh dans le forum Langage
    Réponses: 4
    Dernier message: 14/10/2002, 18h44

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