0

I am trying to parse CSV into Array of structures. Delimiter is ';'. If you look into the code it seems that I filled only first element of the array out of nine that is 9 lines are in my CSV right now. Remaining elements of the array are just 0. Anyone got some advice? Thanks

fileTO.open("imput.csv", ios_base :: app);
fileFROM.open("imput.csv", ios_base :: app);

//IntoCsvThruConsole();

// array of structures from csv

string line;

string sID, stype, scategory, samount, sdate;

int lines = CountExistingLines();

Properties * structure = new Properties[lines];
int counter = 0;
int position = 0;

while (getline(fileFROM, line))
    {
        sID = "";
        samount = "";

     for (int i = 0; i < line.size(); i++)
     {
      if (line[i] == ';')
      {
          position++;
          continue;
      }
      switch (position)
      {
          case 0 : sID = sID + line[i];
          break;

          case 1 : structure[counter].type = structure[counter].type + line[i];
          break;

          case 2 : structure[counter].category = structure[counter].category + line[i];
          break;

          case 3 : samount = samount + line[i];
          break;

          case 4 : structure[counter].date = structure[counter].date + line[i];
          break;
      }
     }
     structure[counter].ID = atoi(sID.c_str());
     structure[counter].amount = atoi(samount.c_str());

    cout << "ID zaznamu: " << structure[counter].ID << endl;
    cout << "Typ: " << structure[counter].type << endl;
    cout << "Kategorie: " << structure[counter].category << endl;
    cout << "Castka: " << structure[counter].amount << endl;
    cout << "Datum: " << structure[counter].date << endl;

    counter++;
    }

delete[] structure;

I have globally initialized struct correctly and also fstreams. Hope it is enough. Thanks

enter image description here

8
  • Could you go more in depth? Commented Dec 1, 2017 at 22:24
  • You should use vectors and not go char by char. Want me to post that solutions? Commented Dec 1, 2017 at 22:32
  • Semi-related : this for loop for (int i = 0; i < line.size(); i++) can be replaced almost entirely with std::stingstream stream(line); and a bunch of lines like std::getline(stream, sID, ';'); to read the tokens. Commented Dec 1, 2017 at 22:32
  • @user4581301 Thats what I was going to say! Commented Dec 1, 2017 at 22:34
  • Very close example: stackoverflow.com/a/20303099/4581301 Actually, I'm going to propose this as a dupe. Commented Dec 1, 2017 at 22:34

1 Answer 1

0

I recommend using Boost.Spirit for such parsing tasks.

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

#include <boost/fusion/adapted.hpp>
#include <boost/spirit/home/x3.hpp>

struct Date
{
    int day;
    int month;
    int year;
};

std::ostream& operator<<(std::ostream& os, Date const &d)
{
    os << d.day << '/' << d.month << '/' << d.year;
    return os;
}

BOOST_FUSION_ADAPT_STRUCT(
    Date,
    day, month, year)

struct Properties
{
    int ID;
    std::string type;
    std::string category;
    int amount;
    Date date;
};

BOOST_FUSION_ADAPT_STRUCT(
    Properties,
    ID, type, category, amount, date)

std::vector<Properties> parse(std::string const &input)
{
    auto iter = input.begin();

    using namespace boost::spirit::x3;

    auto name = rule<class name, std::string>{}
        = lexeme[alpha >> *alpha];

    auto date = rule<class date, Date>{}
        = int_ > '/' > int_ > '/' > int_;

    std::vector<Properties> result;

    bool r = phrase_parse(iter, input.end(),
                          (int_ > ';' > name > ';' > name > ';' > int_ > ';' > date) % eol,
                          space - eol, result);

    if (!r)
    {
        std::string rest(iter, input.end());
        throw std::invalid_argument("Parsing failed at " + rest);
    }

    return result;
}


int main()
{
    // This could be a file instead with std::ifstream
    std::istringstream input;
    input.str(
        "1;TypeA;CategoryA;10;05/12/2017\n"
        "2;TypeB;CategoryA;21;04/12/2017\n"
        "3;TypeB;CategoryB;19;01/12/2017\n"
        "4;TypeA;CategoryA; 6;20/11/2017\n");

    std::vector<Properties> entry = parse(input.str());

    for (auto e :  entry)
    {
        std::cout << "Found the following entries:\n"
                  << "  ID: " << e.ID << "\n"
                  << "  Type: " << e.type << "\n"
                  << "  Category: " << e.category << "\n"
                  << "  Amount: " << e.amount << "\n"
                  << "  Date: " << e.date << "\n";
    }
}

Live example

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.