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 :

Opérateur >> sur ifstream


Sujet :

SL & STL C++

  1. #1
    Membre émérite
    Opérateur >> sur ifstream
    Hello,

    Si j'ai un fichier CSV dont les champs sont séparés par une tabulation, et que le contenu de certains champs peut contenir des espaces, comment faire en sorte que l'opérateur >> ignore les espaces pour ne "tokenizer" qu'en fonction des tabulations ?

  2. #2
    Membre expérimenté
    L'opérateur >> utilise std::isspace(x, stream.getloc()), reference. Faut que tu regardes du côté des locales pour en créer une qui considère que ' ' n'est pas une espace (le site précédent a toutes les références qu'il faut sur les locales pour faire ça).

    Sinon tu peux utiliser une solution de plus haut niveau en lisant toute ta ligne et la lire avec un token_iterator par exemple (dans Boost).

  3. #3
    Membre émérite
    Citation Envoyé par Trademark Voir le message
    Sinon tu peux utiliser une solution de plus haut niveau en lisant toute ta ligne et la lire avec un token_iterator par exemple (dans Boost).
    C'est ce que j'ai fait à une autre occasion, mais là, j'ai besoin de perfs. Même si je sais que les flux ne sont pas encore la panacées, mais comme c'est plus lisible (du moins dans le cas que j'ai à traiter : pas de formatage de flottant).

    Je vais étudier ton autre solution.

  4. #4
    Membre émérite
    Merci pour tes indications, Trademark !

    La solution figure sur cette page.

    EDIT : ça ne va pas ; l'extraction du flux s'arrête quand est rencontré le caractère espace

  5. #5
    Membre expérimenté
    Utilises-tu bien des char au lieu de wchar_t (dans l'exemple) ?
    Est-ce que l'exemple marche (à la base) ?

  6. #6
    Membre expert
    En fait l'exemple est fonctionnel mais la spécialisation de ctype<char> se fiche totalement de certaines fonctions virtuelles dont do_is fait partit (§22.4.1.3.2 petit 5 de la norme C++11).

    Alors du coup j'ai tenté avec un type mychar qui est une structure contenant un char et se cast implicitement en char. J'ai spécialisé ctype avec et définit toute les méthodes virtuelles qui redirigent vers locale.classic().methode_correspondante (vraiment fait à l'arrache).
    Ceci fonctionne mais il faut utiliser des basic_string<mychar>, basic_stringstream<mychar>, etc ce qui n'est pas vraiment pratique :/

  7. #7
    Membre émérite
    Comme l'indique jo_link_noir, la norme de C++ prescrit que ctype<charT> soit accompagné d'une spécialisation ctype<char>, qui fonctionne selon d'autres principes, par souci d'optimisation.

    Je me suis donc inspiré de l'exemple donné en référence, et ai pondu ça :

    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
    #include <iostream>
    #include <vector>
    #include <locale>
    #include <sstream>
     
    // Cette facette ctype ne considère pas le caractère espace comme un... espace
    // Ce caractère est donc ignoré par l'extracteur de flux.
    struct CSV_whitespace : std::ctype<char>
    {
        static const mask* make_table()
        {
            // Fait une copie de la table de localisation
            static std::vector<mask> v(classic_table(), classic_table() + table_size);
     
    	// Déclassifie le caractère espace de la catégorie des caractères vierges
            v[' '] &= ~space;
     
            return &v[0];
        }
     
        CSV_whitespace(std::size_t refs = 0) : ctype(make_table(), false, refs) {}
    };
     
    int main()
    {
        std::string token;
     
        std::string in = "chaine1\tchaine2 chaine3";
     
        std::istringstream s(in);
        s.imbue(std::locale(s.getloc(), new CSV_whitespace()));
        while (s >> token)
        {
            std::cout << "  " << token << '\n';
        }
    }


    Cela fonctionne !