Découpage ligne et stockage dans un vecteur

Résolu/Fermé
cppcdb Messages postés 29 Date d'inscription mardi 18 septembre 2018 Statut Membre Dernière intervention 6 décembre 2018 - Modifié le 18 sept. 2018 à 15:21
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 - 27 sept. 2018 à 15:11
Bonjour tt le monde,

j'ai un fichier qui contient deux valeurs de type double séparés par un point virgule.
à l'aide de getline(), j'ai pu lire mon fichier.
maintenant je cherche à découper cette ligne en fonction de mon délimiteur (le point virgule).
comment je peux faire pour découper cette ligne et stocker le résultat dans un vecteur en utilisant c++?
je reste dipso pour plus de détail

Merci
A voir également:

31 réponses

cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
Modifié le 18 sept. 2018 à 15:31
Bonjour.

Tu peux utiliser à nouveau std::getline en lui précisant ton délimiteur (par défaut il prend \n).

std::ifstream file("toto.txt");
std::string line;
while (std::getline(file, line))
{
  std::istringstream ss(line);
  std::string word;
  while (std::getline(ss, word, ';'))
  {
    std::cout << word << " ";
  }
  std::cout << std::endl;
}


Pour le tableau un simple std::vector<double> suffira. Il ne te restera qu'à convertir les std::string en double et ajouter à ton tableau via un .push_back().

0
cppcdb Messages postés 29 Date d'inscription mardi 18 septembre 2018 Statut Membre Dernière intervention 6 décembre 2018
18 sept. 2018 à 15:40
je vous remercie pour votre réponse rapide et utile :)
en tournant votre code j'ai trouvé ce que j'ai cherché à faire :)
Mais svp est ce que vous pouvez me montrer comment faire pour la partie std::vector<double> c'est pas évident pour moi
Merci d'avance :)
0
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
Modifié le 18 sept. 2018 à 19:25
Exemple d'insertion dans un vecteur: http://www.cplusplus.com/reference/vector/vector/push_back/

Exemple de conversion:
std::string s = "5.2"; 
double d = std::stod(s); 


0
cppcdb Messages postés 29 Date d'inscription mardi 18 septembre 2018 Statut Membre Dernière intervention 6 décembre 2018
Modifié le 21 sept. 2018 à 16:32
j'ai essayé de faire un petit prog pour tester stod :
#include <sstream>
#include <iostream>
#include <vector>
#include <string>

using namespace std;
string s6 ("3.14"); // chaine contenant des chiffres

double d6 = stod(s6);

cout<<"i5="<<i5<<" d6="<<d6<<endl;


mais il y avait un msg d'erreur :

stod was not declared in this scope


svp càd quoi ce msg !!
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
18 sept. 2018 à 16:20
Evite les using namespace, voir: http://0217021.free.fr/portfolio/axel.berardino/articles/bon-usage-using-namespace/

C'est sûrement que tu utilises une vieille version de C++. Mets à jour, et regarde si l'option --std=c++11 est bien activé.
0
cppcdb Messages postés 29 Date d'inscription mardi 18 septembre 2018 Statut Membre Dernière intervention 6 décembre 2018
18 sept. 2018 à 16:32
tt à fait je suis en train d'utiliser une veille version, j'ai pas l'option c++11
0
cppcdb Messages postés 29 Date d'inscription mardi 18 septembre 2018 Statut Membre Dernière intervention 6 décembre 2018
Modifié le 20 sept. 2018 à 15:14
bonjour

suite à mes essais, j'ai réussi à faire un petit code qui lit le fichier, découpe la ligne et stocke le résultat dans un vecteur.

voici mon code et si vous avez des remarques n'hésitez pas à laisser un commentaire.

Merci

#include <iostream>
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <cstdio>
#include <string.h>
#include <cstdlib>

using namespace std;


int main()
{
   ifstream file("C:/Users/AH673B4N/Documents/_Developpement/Dymola/ThreePhaseCableABCDBuilder/Inputs/mesure1.csv");
   string line;
   vector<double> vec;
   while (getline(file, line))
{
       cout << line << endl;
       istringstream ss(line);
       string word;
       while (getline(ss, word,';')){
       double value = strtod(word.c_str(), NULL); // cnversion string to double
       vec.push_back(value); //remplissage du vecteur
  }
}
//Affichage du vecteur
for (int i = 0; i < vec.size(); i++){
        cout << vec[i] << '\n';
 }
 //cout << vec[0] << " " << vec [1] ;
    return 0;
}
0
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
Modifié le 20 sept. 2018 à 16:59
Quelques petites remarques:
- Évite les using namespace std (cf lien donné plus haut dans la discussion), ce n'est pas une bonne idée.
- Tu n'as normalement pas besoin d'inclure quoi que ce soit du C (si tu as du ".h" dans un include system, c'est sûrement évitable).
- La plupart de tes includes ne sont pas nécessaires (tu pourrais en retirer et quand même compiler).
- Il faut penser à gérer les erreurs (pas de fichier, pas de conversion possible, etc...).
- Pour les boucles, tu peux directement utiliser un "for étendu" (for (auto& element : collection){}) au lieu de récupérer la taille du vecteur et devoir gérer un index.

Voici une proposition de correction:
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>

int main()
{
  const std::string filename = "C:/Users/AH673B4N/Documents/_Developpement/Dymola/ThreePhaseCableABCDBuilder/Inputs/mesure1.csv";
  std::ifstream file(filename);
  std::string line;
  std::vector<double> vec;

  if (!file)
  {
    std::cerr << "Can't open file " << filename << std::endl;
    return 1;
  }

  while (std::getline(file, line))
  {
    std::istringstream ss(line);
    std::string word;
    while (std::getline(ss, word, ';'))
    {
      try
      {
      vec.push_back(std::stod(word));
      }
      catch (std::invalid_argument& e)
      {
        std::cerr << "Can't convert " << word << " to double (" << e.what() << ")" << std::endl;
      }
    }
  }

  std::cout << "Vec: ";
  for (auto& val : vec) // on aurait aussi pu écrire for (double val : vec)
    std::cout << val << " ";
  std::cout << std::endl;

  return 0;
}


0
cppcdb Messages postés 29 Date d'inscription mardi 18 septembre 2018 Statut Membre Dernière intervention 6 décembre 2018
20 sept. 2018 à 15:43
je vous remercie de tt mon cœur :)
0
cppcdb Messages postés 29 Date d'inscription mardi 18 septembre 2018 Statut Membre Dernière intervention 6 décembre 2018
21 sept. 2018 à 12:55
Bonjour
Svp j'ai une autre question, si par exemple j'ai un fichier.csv mais qui contient plusieurs lignes et plusieurs colonnes (par exemple 200 lignes et 20 colonnes), comment je peut faire pour transformer ce fichier en une matrice M[i][j]? est ce que ça sera le même principe qu'auparavant ?
Merci
0
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
21 sept. 2018 à 13:39
Ça sera exactement le même principe. Au lieu d'avoir un std::vector<double>, tu auras un std::vector<std::vector<double>>. Ce n'est pas plus compliqué.

Alternativement, pour lire du CSV, tu peux aussi utiliser ce projet:
https://github.com/ben-strasser/fast-cpp-csv-parser

Au choix.
0
cppcdb Messages postés 29 Date d'inscription mardi 18 septembre 2018 Statut Membre Dernière intervention 6 décembre 2018
21 sept. 2018 à 15:21
svp est ce qu'il y a une fonction qui permet d'ignorer la première ligne de mon fichier (la première ligne représente les entêtes je vais pas l'utiliser dans la suite de mon prog)

Merci :)
0
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
21 sept. 2018 à 15:37
Vu que c'est toi qui boucle ligne à ligne, il te suffit de compter les lignes. Si la ligne est celle que tu ne veux pas, alors il te suffit de passer à l'itération suivante (soit avec un gros "if", ou alors avec un "continue").
0
cppcdb Messages postés 29 Date d'inscription mardi 18 septembre 2018 Statut Membre Dernière intervention 6 décembre 2018
Modifié le 21 sept. 2018 à 17:12
je vais vous montrer mon code et dites moi svp j'ai des grands doutes !! je suis pas sure de mon logique
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <string.h>

int main()
{
  const std::string filename = "C:/Users/AH673B4N/Documents/_Developpement/Dymola/ThreePhaseCableABCDBuilder/Inputs/Measurements.csv";
  std::ifstream file(filename);
  std::string line;
  std::vector<std::vector<double>> vec;
  int lines = 0;

  if (!file) // tester l'existance du fichier et la possibilité d'ouverture
  {
    std::cerr << "Can't open file " << filename << std::endl;
    return 1;
  }

while(!file.eof()) // eof end of file
        {
    std::getline (file, line);
    lines++; //incrémentation des lignes
    std::istringstream ss(line);
    std::string word;
    while (std::getline(ss, word, ';'))
    {
      try
      {
          for (int i =1; i<lines; i++)
          {
      vec.push_back(std::vector<double>(std::stod(word)));
          }

      }
      catch (std::invalid_argument& e)
      {
        std::cerr << "Can't convert " << word << " to double (" << e.what() << ")" << std::endl;
      }
    }
  }

  std::cout << "Vec: ";
  for (auto& val : vec) // on aurait aussi pu écrire for (double val : vec)
{
  std::cout << val << " ";
  //std::cout << vec [1]<< std:: endl;
  std::cout << std::endl;
  //std::cout << vec [0]+vec[1] << std::endl; // on eut faire des opérations sur les cases du mon tableau, les cases sont accessibles
}


  return 0;
}


en plus j'ai un msg d'erreur : no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream<char>}' and 'std::vector<double>')

j'arrive pas à comprendre le msg

dsl pour les questions bêtes !
0
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
21 sept. 2018 à 17:14
Plusieurs soucis:
- Tu utilises "lignes" comme étant la taille de tes colonnes. A chaque ligne, tu vas essayer de lire de plus en plus de colonnes. Il y a une erreur de raisonnement ici.
- Le message d'erreur que tu as, vient du fait que dans "val : vec", val n'est plus un double, mais un std::vector<double>. Or tu ne peux pas l'afficher directement. Il te faut une autre boucle imbriqué pour en afficher les éléments.
0
cppcdb Messages postés 29 Date d'inscription mardi 18 septembre 2018 Statut Membre Dernière intervention 6 décembre 2018
Modifié le 24 sept. 2018 à 15:47
Bonjour,

Je vous remercie pour votre réponse.
J'ai fait mon prog d'une autre manière. Le prog fonctionne bien mais je suis tjrs à l'écoute de vos conseils :)

Merci.

#include <string>
#include <sstream>
#include <iostream>
#include <vector>
#include <fstream>

int main()
{
    const std::string filename = "C:/Users/Measurements.csv";
    std::ifstream in(filename); // open the file
    std::string line, field;
    std::vector <std::vector <string> > array;  // the 2D array
    std::vector<string> v;

    if (!in) // error if the file doesn't exist
  {
    std::cerr << "Can't open file " << filename << std::endl;
    return 1;
  }

    while ( std::getline(in,line) )    // get next line in file
    {
        v.clear();
        std::stringstream ss(line);

        while (std::getline(ss,field,';'))  // break line into comma delimitted fields
        {
            v.push_back(field);  // add each field to the 1D array
        }

        array.push_back(v);  // add the 1D array to the 2D array
    }

    // print out what was read in

    for (size_t i=0; i<array.size(); ++i)
    {
        for (size_t j=0; j<array[i].size(); ++j)
        {
            std:: cout << array[i][j] << " | "; // (separate fields by |)
        }
        std:: cout << "\n";
    }

    //std:: cout << "array[1][3]= " << array[1][3] <<etd::endl;

    return 0;
}
0
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
Modifié le 24 sept. 2018 à 17:01
Plusieurs soucis:
- Pas de check d'erreur (lors de la conversion). Donc ton programme peut planter ou faire n'importe quoi si tu lui donnes un fichier pas compatible. Ça devrait être géré.
- Pas besoin de clear ton vecteur à chaque fois. Déclare une variable dans un scope restreint, et elle n'existera que dans ce scope. D'une manière générale, ne pas déclarer des variables en haut de ta fonction, mais au moment où tu en as besoin.
- Attention, tu ne vérifies pas si le vecteur à insérer est vide quand tu l'insères dans le premier vecteur (c'est-à-dire que tu as sûrement un vecteur final contenant plein de tableaux vides potentiels sur des lignes incorrectes).
- Pour afficher ton tableau, une simple double boucle de for étendu suffisait.

#include <string>
#include <sstream>
#include <iostream>
#include <vector>
#include <fstream>

int main()
{
  const std::string filename = "C:/Users/Measurements.csv";
  std::ifstream file(filename);

  if (!file)
  {
    std::cerr << "Can't open file " << filename << std::endl;
    return 1;
  }

  std::string line;
  std::vector<std::vector<double>> array;
  while (std::getline(file, line))
  {
    std::vector<double> v;
    std::string field;
    std::stringstream ss(line);
    while (std::getline(ss, field, ';'))
    {
      try
      {
        v.push_back(std::stod(field));
      }
      catch (std::invalid_argument& e)
      {
        std::cerr << "Can't convert " << field << " to double (" << e.what() << ")" << std::endl;
        continue;
      }
    }
    if (!v.empty()) // Prevent invalid lines to display empty lines later
      array.push_back(v);
  }

  std::cout << "Vec:\n";
  for (auto& vec : array)
  {
    for (auto& value : vec)
      std::cout << value << "|";
    std::cout << std::endl;
  }

  return 0;
}


PS: utilise <code cpp> au lieu de <code> pour activer la coloration syntaxique.

0
cppcdb Messages postés 29 Date d'inscription mardi 18 septembre 2018 Statut Membre Dernière intervention 6 décembre 2018
25 sept. 2018 à 09:44
Bonjour,

vous avez raison, mais il y a qlq soucis:

1- le fichier contient des entêtes, comment je peux faire pour parcourir mes lignes afin de débarrasser de la première ligne lors de la conversion vers "double"?
2- les doubles de mon fichier sont séparés par une virgule et non par un point, du coup comme résultat j'ai obtenu un vecteur contenant juste la partie entière de chaque valeur. or moi je dois récupérer la valeur telle qu'elle est !
Merci pour votre aide :)

0
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
Modifié le 25 sept. 2018 à 10:41
1) Un entête commence normalement par #, donc il suffit de ne pas lire une ligne qui commence par cela. Si ce n'est pas le cas, le code le gère déjà, puisque toute ligne non convertie n'est pas dans le tableau final. Les erreurs sont uniquement affichées et n'affectent pas le tableau résultat.
2) Là, c'est assez compliqué à faire. En fait, un double prend un "." et non une ",". Dès le moment ou tu veux un double particulier (par exemple si tu décides que 3.14 s'écrit maintenant 3,14 ou 3#14 ou 3-14, ou 3$14), alors ce n'est plus un double ! Tu dois alors créer un convertisseur spécial qui précise quel est le séparateur voulu. Il faut modifier la "locale" (langue) en cours et lui dire que le séparateur est maintenant ",". La syntaxe n'est pas aisée du tout. Il faut écrire sa propre fonction std::stod (que j'ai appelé "comaStod") et utiliser une locale personnalisée.

#include <string>
#include <sstream>
#include <iostream>
#include <vector>
#include <fstream>
#include <clocale>

template <class charT, charT sep>
class punct_facet: public std::numpunct<charT> {
protected:
  charT do_decimal_point() const { return sep; }
};

double comaStod(std::string const& s)
{
  std::istringstream iss(s);
  iss.imbue(std::locale(std::cout.getloc(), new punct_facet<char, ','>));
  double d;
  if (!(iss >> d))
    throw std::invalid_argument("invalid double");

  return d;
}

int main()
{
  const std::string filename = "C:/Users/Measurements.csv";
  std::ifstream file(filename);

  if (!file)
  {
    std::cerr << "Can't open file " << filename << std::endl;
    return 1;
  }

  std::string line;
  std::vector<std::vector<double>> array;
  while (std::getline(file, line))
  {
    // Ignore line starting with #
    if (line.empty() || line[0] == '#')
      continue;
    std::vector<double> v;
    std::string field;
    std::stringstream ss(line);
    while (std::getline(ss, field, ';'))
    {
      try
      {
        v.push_back(comaStod(field));
      }
      catch (std::invalid_argument& e)
      {
        std::cerr << "Can't convert " << field << " to double (" << e.what() << ")" << std::endl;
        continue;
      }
    }
    if (!v.empty())
      array.push_back(v);
  }

  std::cout << "Vec:\n";
  for (auto& vec : array)
  {
    for (auto& value : vec)
      std::cout << value << "|";
    std::cout << std::endl;
  }

  return 0;
}


0
cppcdb Messages postés 29 Date d'inscription mardi 18 septembre 2018 Statut Membre Dernière intervention 6 décembre 2018
25 sept. 2018 à 10:59
1000 merci à vous :)
concernant la première ligne, elle ne commence pas par #. En fait, elle contient 16 colonnes nommés comme suit :

Freq(Hz) R1 (Ohm) R2 (Ohm) R3 (Ohm) L1(Henry) L2(Henry) L3(Henry) Le1(Henry) Le2(Henry) Le3(Henry) CA(Farad) CB(Farad) CC(Farad) CD(Farad) CE (Farad) CF(Farad)

c'est vrai cette ligne non convertie n'est pas mise dans le tableau final. Juste des erreurs sont affichées mais qd mm je vais essayer d'ignorer cette ligne pour avoir un affichage propre :)

Je vous remercie encore une fois :)
0
Rejoignez-nous