mars_lib  0.1.0.3dc76ee85e09
Modular and Robust Sensor-Fusion
read_csv.h
Go to the documentation of this file.
1 // Copyright (C) 2021 Christian Brommer, Control of Networked Systems, University of Klagenfurt, Austria.
2 //
3 // All rights reserved.
4 //
5 // This software is licensed under the terms of the BSD-2-Clause-License with
6 // no commercial use allowed, the full terms of which are made available
7 // in the LICENSE file. No license in patents is granted.
8 //
9 // You can contact the author at <christian.brommer@ieee.org>
10 
11 #ifndef READ_CSV_H
12 #define READ_CSV_H
13 
14 #include <algorithm>
15 #include <fstream>
16 #include <iomanip>
17 #include <iostream>
18 #include <map>
19 #include <sstream>
20 #include <string>
21 #include <vector>
23 
24 namespace mars
25 {
26 using CsvDataType = std::map<std::string, std::vector<double>>;
27 using HeaderMapType = std::map<int, std::string>;
28 
29 class ReadCsv
30 {
31  char delim{ ',' };
33 
34 public:
35  ReadCsv(CsvDataType* csv_data, const std::string& file_path, char delim_ = ',') : delim(delim_)
36  {
37  if (!mars::filesystem::IsFile(file_path))
38  {
39  std::cout << "ReadCsv(): [Warning] File " << file_path << " does not exist." << std::endl;
40  exit(EXIT_FAILURE);
41  }
42 
43  file_.open(file_path);
44 
45  // Check for header
46  const int first_value_row = check_for_header();
47 
48  // Initialize CSV data type
49  const int rows = get_rows();
50 
51  if (first_value_row < 1)
52  {
53  std::cout << "ReadCsv():Error: No header in CSV file" << std::endl;
54  exit(EXIT_FAILURE);
55  }
56 
57  header_map = get_header(first_value_row - 1);
58 
59  // Set line counter to first valued row
60  if (first_value_row > 0)
61  {
62  set_line_couter_of_file(first_value_row);
63  }
64 
65  CsvDataType csv_data_int;
66  for (auto it = header_map.begin(); it != header_map.end(); it++)
67  {
68  csv_data_int[it->second].resize(rows - 1, 0.0);
69  }
70 
71  // Read columns associated to header tokens
72  std::string line;
73  int line_counter = 0;
74  int parsed_row_counter = first_value_row; // header already parsed.
75 
76  while (std::getline(file_, line))
77  {
78  std::stringstream row_stream(line);
79  std::string token;
80  int column_counter = 0;
81 
82  double item;
83  while (std::getline(row_stream, token, delim))
84  {
85  if (column_counter >= (int)header_map.size())
86  {
87  std::cout << "ReadCsv(): Warning: too many entries in row!" << std::endl;
88  ++column_counter; // to indicate a corrupted row
89  break;
90  }
91 
92  std::istringstream is(token);
93  is >> item;
94  csv_data_int[header_map[column_counter]][line_counter] = (item);
95  ++column_counter;
96  }
97 
98  // check if row was corrupted, if so, overwrite current line with the next one
99  if (column_counter != (int)header_map.size())
100  {
101  std::cout << "ReadCsv(): Warning: corrupted row=" << parsed_row_counter << " will be skipped!" << std::endl;
102  }
103  else
104  {
105  line_counter++;
106  }
107 
108  // increment parsed row counter
109  parsed_row_counter++;
110  }
111 
112  // shrink to the actual size
113  for (auto it = header_map.begin(); it != header_map.end(); it++)
114  {
115  csv_data_int[it->second].resize(line_counter);
116  }
117 
118  file_.close();
119 
120  *csv_data = csv_data_int;
121  }
122 
123 private:
124  std::ifstream file_;
125 
126  HeaderMapType get_header(const int& row = 0)
127  {
129 
130  HeaderMapType header_data;
131 
132  int count = 0;
133  std::string line;
134  std::getline(file_, line);
135  std::stringstream row_stream(line);
136  std::string token;
137 
138  while (std::getline(row_stream, token, delim))
139  {
140  token.erase(remove_if(token.begin(), token.end(), isspace), token.end());
141 
142  header_data[count] = token;
143  count++;
144  }
145 
146  file_.clear(); // reset line counter
147  file_.seekg(0, std::ios::beg);
148  return header_data;
149  }
150 
152  {
153  int count = 0;
154  std::string line;
155  while (std::getline(file_, line))
156  {
157  if (std::isdigit(line[line.find_first_not_of(" \t")]))
158  {
159  break;
160  }
161 
162  ++count;
163  }
164 
165  file_.clear(); // reset line counter
166  file_.seekg(0, std::ios::beg);
167  return count;
168  }
169 
170  void set_line_couter_of_file(const int& line_number)
171  {
172  file_.clear(); // reset line counter
173  file_.seekg(0, std::ios::beg);
174 
175  std::string line;
176  for (int k = 0; k < line_number; k++)
177  {
178  std::getline(file_, line);
179  }
180  }
181 
182  int get_rows()
183  {
184  int count = 0;
185  std::string line;
186  while (std::getline(file_, line))
187  {
188  ++count;
189  }
190  file_.clear(); // reset line counter
191  file_.seekg(0, std::ios::beg);
192  return count;
193  }
194 };
195 } // namespace mars
196 
197 #endif // READ_CSV_H
Definition: read_csv.h:30
HeaderMapType get_header(const int &row=0)
Definition: read_csv.h:126
ReadCsv(CsvDataType *csv_data, const std::string &file_path, char delim_=',')
Definition: read_csv.h:35
char delim
Definition: read_csv.h:31
int check_for_header()
Definition: read_csv.h:151
void set_line_couter_of_file(const int &line_number)
Definition: read_csv.h:170
std::ifstream file_
Definition: read_csv.h:124
int get_rows()
Definition: read_csv.h:182
HeaderMapType header_map
Definition: read_csv.h:32
static bool IsFile(const std::string &name)
filesystem::IsFile Check if the given path results in a file
Definition: buffer.h:27
std::map< std::string, std::vector< double > > CsvDataType
Definition: read_csv.h:26
std::map< int, std::string > HeaderMapType
Definition: read_csv.h:27