Анализ CSV с оператором извлечения istream: Как обнаружить пропущенные значения поля? - PullRequest
0 голосов
/ 11 октября 2019

Я пытаюсь выполнить простой анализ csv (разделенных пробелами) с использованием istream << (оператор). </p>

Мой формат файла csv выглядит следующим образом:

file.csv


/ names |значение |интервал |

name1 11 1

name2 22 2

name3 33 3


Мой пример кода выглядит следующим образом:

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;
    }
}

мой код прекрасно работает с пустыми строками или комментариями или случайными пробелами, но он потерпит неудачу, если одно из значений будет отсутствовать. Например, в строке name2, если значение 22 отсутствует, оператор извлечения будет интерпретировать 2, поскольку значение и интервал будут установлены в 0, и он не будет продолжать синтаксический анализ следующих строк.

Я хотел бызнать, существует ли простой обходной путь для обнаружения пропущенных полей в файле CSV. Было бы хорошо, если бы я проигнорировал эту строку, где какое-то поле отсутствует, но анализ продолжается со следующими строками.

Я рассмотрел некоторые параметры, такие как istream :: get, getline, gcount, peek, но яне мог придумать ни одного легкого решения. Пока я не могу изменить сам формат csv.

1 Ответ

0 голосов
/ 11 октября 2019

Для таких случаев лучше:

  1. Читать содержимое файла построчно.
  2. Обрабатывать каждую строку для извлечения соответствующих данных.

Ваш код может быть преобразован в:

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

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;
   }
}
...