-1

I am trying to do a simple csv(space seperated values) parsing using istream <<(operator).

My file csv file format looks as follows:

file.csv


/names | value | interval |

name1 11 1

name2 22 2

name3 33 3


My sample code looks like below:

fstream fin
std::pair<std::string, struct>entry{};
/* handle empty file path */
if(confPath != nullptr)
{
  fin.open(confPath,ios::in);

  /* handled no file on the specified path */
  if(fin)
    {
  //check if the file is empty
  if(fin.peek() != std::ifstream::traits_type::eof())
    {
      while(fin >> entry.first)
        {
       /* Take care of comments, empty lines and spaces */
       if(entry.first[0] != '#' && entry.first[0] != '/' && entry.first[0] != '\n')
        {
          /* Populate the structure with properties from the csv file */
          fin >> entry.second.value >> entry.second.interval >> endl;
        }
      else
        {
          fin.ignore(256, '\n');
        }
      }
  }
  else
    {
      cout << "file is empty" << endl;
    }
  }
  else
    {
     cout << "file does not exists" << endl;
    }
}

my code works perfectly fine with empty lines or comments or random spaces but it will fail if one of the values are missing. For example, in name2 line if the value 22 is missing, then the extraction operator will interpret 2 as the value and interval will be set to 0 and it does not continue parsing the next lines.

I would like to know if there exists a simple work-around to detect the missing fields in the csv file. It would be fine for me to ignore that one line where some field is missing but the parsing proceeds with the following lines.

I have looked at some options like istream::get, getline, gcount, peek but I could not come up with any easy solution. For now, I cannot change the csv format itself.

charansai
  • 137
  • 13

1 Answers1

0

For such use cases, it's better to:

  1. Read the contents of the file line by line.
  2. Process each line to extract the relevant data.

Your code could be transformed to:

// ------------------------------------------------------------------------------

bool isCommentLine(std::string const& line)
{
   return (!line.empty() && (line[0] == '#' || line[0] = '/') );
}

bool isEmtpyLine(std::string const& line)
{
   // This function can get more involved depending on how you define an emtpy line.
   // E.g. you could say a line is an empty line if all it has are whitespace characters.

   return line.emtpy();
}

bool canIgnoreLine(std::string const& line)
{
   return ( isCommentLine(line) || isEmtpyLine(line) );
}

void processLine(std::string const& line)
{
   if ( canIgnoreLine(line) )
   {
      return;
   }

   // Parse the contents of the line using a stringstream.
   std::istringstream str(line);

   // Such as ...

   // struct what? That needs to be changed.
   std::pair<std::string, struct> entry{};
   if ( str >> entry.first >> entry.second.value >> entry.second.interval )
   {
      // Got all the values successfully.
      // Use them
   }
   else
   {
      // Deal with the error.
   }
}

// ------------------------------------------------------------------------------

fstream fin
/* handle empty file path */
if(confPath != nullptr)
{
   fin.open(confPath,ios::in);

   /* handled no file on the specified path */
   if(fin)
   {
      std::string line;
      while ( getline(fin, line) )
      {
         processLine(line)
      }
   }

   else
   {
      cout << "file does not exists" << endl;
   }
}
R Sahu
  • 204,454
  • 14
  • 159
  • 270