web-dev-qa-db-fra.com

C++ Lisez le fichier ligne par ligne, puis divisez chaque ligne en utilisant le délimiteur

Je veux lire un fichier txt ligne par ligne et après avoir lu chaque ligne, je souhaite fractionner la ligne en fonction de l'onglet "\ t" et ajouter chaque partie à un élément d'une structure.

mon struct est 1 * caractère et 2 * int

struct myStruct
{
    char chr;
    int v1;
    int v2;
}

où chr peut contenir plus d'un caractère.

Une ligne devrait être quelque chose comme: 

randomstring TAB number TAB number NL
20
sikas

Essayer:
Remarque: si chr peut contenir plus d’un caractère, utilisez une chaîne pour le représenter.

std::ifstream file("plop");
std::string   line;

while(std::getline(file, line))
{
    std::stringstream   linestream(line);
    std::string         data;
    int                 val1;
    int                 val2;

    // If you have truly tab delimited data use getline() with third parameter.
    // If your data is just white space separated data
    // then the operator >> will do (it reads a space separated Word into a string).
    std::getline(linestream, data, '\t');  // read up-to the first tab (discard tab).

    // Read the integers using the operator >>
    linestream >> val1 >> val2;
}
27
Martin York

À moins que vous n'ayez l'intention d'utiliser également cette structure pour C, je remplacerais le caractère * prévu par std :: string.

Ensuite, pour pouvoir le lire depuis un flux, j'écrirais la fonction suivante:

std::istream & operator>>( std::istream & is, myStruct & my )
{
    if( std::getline(is, my.str, '\t') )
       return is >> my.v1 >> my.v2;
}

avec str comme membre std :: string. Ceci écrit dans votre structure, en utilisant tab comme premier délimiteur, puis tout délimiteur d'espaces blancs le fera avant les deux entiers suivants. (Vous pouvez le forcer à utiliser l'onglet).

Pour lire ligne par ligne, vous pouvez soit continuer la lecture, soit lire la ligne en premier dans une chaîne, puis placer la chaîne dans un flux istring et appeler la personne susmentionnée.

Vous devrez décider comment gérer les lectures ayant échoué. Toute lecture ayant échoué ci-dessus laisserait le flux en état d'échec.

3
CashCow
std::ifstream in("fname");
while(in){
    std::string line;
    std::getline(in,line);
    size_t lasttab=line.find_last_of('\t');
    size_t firsttab=line.find_last_of('\t',lasttab-1);
    mystruct data;
    data.chr=line.substr(0,firsttab).c_str();
    data.v1=atoi(line.substr(firsttab,lasttab).c_str());
    data.v2=atoi(line.substr(lasttab).c_str());
}
2
flownt

J'ai eu quelques difficultés à suivre certaines des suggestions ici. Je publie donc un exemple complet de surcharge des opérateurs d'entrée et de sortie pour une structure sur un fichier délimité par des tabulations. En prime, il prend aussi l'entrée soit de stdin, soit d'un fichier fourni via les arguments de la commande.

Je pense que c'est aussi simple que cela devient en adhérant à la sémantique des opérateurs.


pairwise.h

#ifndef PAIRWISE_VALUE
#define PAIRWISE_VALUE

#include <string>
#include <iostream>

struct PairwiseValue
{
    std::string labelA;
    std::string labelB;
    float value;
};

std::ostream& operator<<(std::ostream& os, const PairwiseValue& p);

std::istream& operator>>(std::istream& is, PairwiseValue& p);

#endif

pairwise.cc

#include "pairwise.h"

std::ostream& operator<<(std::ostream& os, const PairwiseValue& p)
{
    os << p.labelA << '\t' << p.labelB << '\t' << p.value << std::endl;
    return os;
}

std::istream& operator>>(std::istream& is, PairwiseValue& p)
{
    PairwiseValue pv;

    if ((is >> pv.labelA >> pv.labelB >> pv.value))
    {
        p = pv;
    }

    return is;
}

test.cc

#include <fstream>
#include "pairwise.h"

int main(const int argc, const char* argv[])
{
    std::ios_base::sync_with_stdio(false); // disable synch with stdio (enables input buffering)

    std::string ifilename;
    if (argc == 2)
    {
        ifilename = argv[1];
    }

    const bool use_stdin = ifilename.empty();
    std::ifstream ifs;
    if (!use_stdin)
    {
        ifs.open(ifilename);

        if (!ifs)
        {
            std::cerr << "Error opening input file: " << ifilename << std::endl;
            return 1;
        }
    }

    std::istream& is = ifs.is_open() ? static_cast<std::istream&>(ifs) : std::cin;

    PairwiseValue pv;

    while (is >> pv)
    {
        std::cout << pv;
    }

    return 0;
}

Compiler

g++ -c pairwise.cc test.cc
g++ -o test pairwise.o test.o

Utilisation

./test myvector.tsv
cat myvector.tsv | ./test
0
vallismortis