minicsv.h
Go to the documentation of this file.
1 // The MIT License (MIT)
2 // Minimalistic CSV Streams 1.7.9
3 // Copyright (C) 2014 - 2016, by Wong Shao Voon (shaovoon@yahoo.com)
4 //
5 // http://opensource.org/licenses/MIT
6 //
7 // version 1.2 : make use of make_shared
8 // version 1.3 : fixed: to when reading the last line and it does not have linefeed
9 // added: skip_1st_line and skip_line functions to ifstream class
10 // version 1.4 : Removed the use of smart ptr.
11 // version 1.5 : Performance increase on writing without flushing every line.
12 // version 1.6 : Add string streams
13 // version 1.7 : You MUST specify the escape/unescape string when calling set_delimiter. Option to surround/trim string with quotes
14 // version 1.7.1 : Add stream operator overload usage in example.cpp
15 // Disable the surround/trim quote on text by default
16 // version 1.7.2 : Stream operator overload for const char*
17 // version 1.7.3 : Add num_of_delimiter method to ifstream and istringstream
18 // Fix g++ compilation errors
19 // version 1.7.4 : Add get_rest_of_line
20 // version 1.7.5 : Add terminate_on_blank_line variable. Set to false if your file format has blank lines in between.
21 // version 1.7.6 : Ignore delimiters within quotes during reading when enable_trim_quote_on_str is true;
22 // version 1.7.7 : Fixed multiple symbol linkage errors
23 // version 1.7.8 : Add quote escape/unescape. Default is """
24 // version 1.7.9 : Reading UTF-8 BOM
25 // version 1.7.10 : separator class for the stream, so that no need to call set_delimiter repeatedly if delimiter keep changing
26 // version 1.7.11 : Fixed num_of_delimiters function: do not count delimiter within quotes
27 // version 1.8.0 : Add meaningful error message for data conversion during reading
28 // version 1.8.1 : Put under the mini namespace
29 
30 //#define USE_BOOST_LEXICAL_CAST
31 
32 #ifndef MiniCSV_H
33  #define MiniCSV_H
34 
35 #include <string>
36 #include <sstream>
37 #include <fstream>
38 #include <algorithm>
39 #include <stdexcept>
40 
41 #ifdef USE_BOOST_LEXICAL_CAST
42 # include <boost/lexical_cast.hpp>
43 #endif
44 
45 #define NEWLINE '\n'
46 
47 namespace mini
48 {
49 
50  namespace csv
51  {
52  inline std::string const & replace(std::string & src, std::string const & to_find, std::string const & to_replace)
53  {
54  size_t pos = 0;
55  while (std::string::npos != pos)
56  {
57  pos = src.find(to_find, pos);
58 
59  if (std::string::npos != pos)
60  {
61  src.erase(pos, to_find.size());
62  src.insert(pos, to_replace);
63  pos += to_replace.size();
64  }
65  }
66 
67  return src;
68  }
69 
70  inline std::string trim_right(const std::string& str, const std::string& trimChars)
71  {
72  std::string result = "";
73  size_t endpos = str.find_last_not_of(trimChars);
74  if (std::string::npos != endpos)
75  {
76  result = str.substr(0, endpos + 1);
77  }
78  else
79  result = str;
80 
81  return result;
82  }
83 
84  inline std::string trim_left(const std::string& str, const std::string& trimChars)
85  {
86  std::string result = "";
87 
88  size_t startpos = str.find_first_not_of(trimChars);
89  if (std::string::npos != startpos)
90  {
91  result = str.substr(startpos);
92  }
93  else
94  result = str;
95 
96  return result;
97  }
98 
99  inline std::string trim(const std::string& str, const std::string& trimChars)
100  {
101  return trim_left(trim_right(str, trimChars), trimChars);
102  }
103 
104  class sep // separator class for the stream, so that no need to call set_delimiter
105  {
106  public:
107  sep(const char delimiter_, const std::string& escape_) : delimiter(delimiter_), escape(escape_) {}
108 
109  const char get_delimiter() const { return delimiter; }
110  const std::string& get_escape() const { return escape; }
111  private:
112  const char delimiter;
113  const std::string escape;
114  };
115 
116  class ifstream
117  {
118  public:
119  ifstream()
120  : str("")
121  , pos(0)
122  , delimiter(",")
123  , unescape_str("##")
124  , trim_quote_on_str(false)
125  , trim_quote('\"')
126  , terminate_on_blank_line(true)
127  , quote_unescape("&quot;")
128  , has_bom(false)
129  , first_line_read(false)
130  , filename("")
131  , line_num(0)
132  , token_num(0)
133  {
134  }
135  ifstream(const char * file)
136  {
137  open(file);
138  }
139  void open(const char * file)
140  {
141  init();
142  filename = file;
143  istm.open(file, std::ios_base::in);
144  read_bom();
145  }
146  void read_bom()
147  {
148  char tt[3] = { 0, 0, 0 };
149 
150  istm.read(tt, sizeof(tt));
151 
152  if (tt[0] == (char)0xEF || tt[1] == (char)0xBB || tt[2] == (char)0xBF) // not the correct BOM, so reset the pos to beginning (file might not have BOM)
153  has_bom = true;
154 
155  istm.seekg(0, istm.beg);
156  }
157  void init()
158  {
159  str = "";
160  pos = 0;
161  delimiter = ',';
162  unescape_str = "##";
163  trim_quote_on_str = false;
164  trim_quote = '\"';
165  terminate_on_blank_line = true;
166  has_bom = false;
167  first_line_read = false;
168  filename = "";
169  line_num = 0;
170  token_num = 0;
171  }
172  void close()
173  {
174  istm.close();
175  }
176  bool is_open()
177  {
178  return istm.is_open();
179  }
180  void enable_trim_quote_on_str(bool enable, char quote, const std::string& unescape = "&quot;")
181  {
182  trim_quote_on_str = enable;
183  trim_quote = quote;
184  quote_unescape = unescape;
185  }
186  // eof is replaced by read_line
187  //bool eof() const
188  void set_delimiter(char delimiter_, std::string const & unescape_str_)
189  {
190  delimiter = delimiter_;
191  unescape_str = unescape_str_;
192  }
193  std::string const & get_delimiter() const
194  {
195  return delimiter;
196  }
197  std::string const & get_unescape_str() const
198  {
199  return unescape_str;
200  }
201  void skip_line()
202  {
203  if (!istm.eof())
204  {
205  std::getline(istm, str);
206  pos = 0;
207 
208  if (first_line_read == false)
209  {
210  first_line_read = true;
211  }
212  }
213  }
214  bool read_line()
215  {
216  this->str = "";
217  while (!istm.eof())
218  {
219  std::getline(istm, this->str);
220  pos = 0;
221 
222  if (first_line_read == false)
223  {
224  first_line_read = true;
225  if (has_bom)
226  {
227  this->str = this->str.substr(3);
228  }
229  }
230 
231  if (this->str.empty())
232  {
233  if (terminate_on_blank_line)
234  break;
235  else
236  continue;
237  }
238 
239  ++line_num;
240  token_num = 0;
241  return true;
242  }
243  return false;
244  }
245  std::string get_delimited_str()
246  {
247  std::string str = "";
248  char ch = '\0';
249  bool within_quote = false;
250  do
251  {
252  if (pos >= this->str.size())
253  {
254  this->str = "";
255 
256  ++token_num;
257  return unescape(str);
258  }
259 
260  ch = this->str[pos];
261  if (trim_quote_on_str)
262  {
263  if (within_quote == false && ch == trim_quote && ((pos > 0 && this->str[pos - 1] == delimiter[0]) || pos == 0))
264  within_quote = true;
265  else if (within_quote && ch == trim_quote)
266  within_quote = false;
267  }
268 
269  ++(pos);
270 
271  if (ch == delimiter[0] && within_quote == false)
272  break;
273  if (ch == '\r' || ch == '\n')
274  break;
275 
276  str += ch;
277  } while (true);
278 
279  ++token_num;
280  return unescape(str);
281  }
282  std::string unescape(std::string & src)
283  {
284  src = unescape_str.empty() ? src : replace(src, unescape_str, delimiter);
285 
286  if (trim_quote_on_str)
287  {
288  std::string s = trim(src, std::string(1, trim_quote));
289  return replace(s, quote_unescape, std::string(1, trim_quote));
290  }
291 
292  return src;
293  }
294  size_t num_of_delimiter() const
295  {
296  if (delimiter.size() == 0)
297  return 0;
298 
299  size_t cnt = 0;
300  if (trim_quote_on_str)
301  {
302  bool inside_quote = false;
303  for (size_t i = 0; i < str.size(); ++i)
304  {
305  if (str[i] == trim_quote)
306  inside_quote = !inside_quote;
307 
308  if (!inside_quote)
309  {
310  if (str[i] == delimiter[0])
311  ++cnt;
312  }
313  }
314  }
315  else
316  {
317  cnt = std::count(str.begin(), str.end(), delimiter[0]);
318  }
319  return cnt;
320  }
321  std::string get_rest_of_line() const
322  {
323  return str.substr(pos);
324  }
325  const std::string& get_line() const
326  {
327  return str;
328  }
329  void enable_terminate_on_blank_line(bool enable)
330  {
331  terminate_on_blank_line = enable;
332  }
333  bool is_terminate_on_blank_line() const
334  {
335  return terminate_on_blank_line;
336  }
337  std::string error_line(const std::string& token)
338  {
339  std::ostringstream is;
340  is << "csv::ifstream Conversion error at line no.:" << line_num << ", filename:" << filename << ", token position:" << token_num << ", token:" << token;
341  return is.str();
342  }
343 
344  private:
345  std::ifstream istm;
346  std::string str;
347  size_t pos;
348  std::string delimiter;
349  std::string unescape_str;
350  bool trim_quote_on_str;
351  char trim_quote;
352  bool terminate_on_blank_line;
353  std::string quote_unescape;
354  bool has_bom;
355  bool first_line_read;
356  std::string filename;
357  size_t line_num;
358  size_t token_num;
359  };
360 
361  class ofstream
362  {
363  public:
364 
365  ofstream()
366  : after_newline(true)
367  , delimiter(",")
368  , escape_str("##")
369  , surround_quote_on_str(false)
370  , surround_quote('\"')
371  , quote_escape("&quot;")
372  {
373  }
374  ofstream(const char * file)
375  {
376  open(file);
377  }
378  void open(const char * file)
379  {
380  init();
381  ostm.open(file, std::ios_base::out);
382  }
383  void init()
384  {
385  after_newline = true;
386  delimiter = ',';
387  escape_str = "##";
388  surround_quote_on_str = false;
389  surround_quote = '\"';
390  quote_escape = "&quot;";
391  }
392  void flush()
393  {
394  ostm.flush();
395  }
396  void close()
397  {
398  ostm.close();
399  }
400  bool is_open()
401  {
402  return ostm.is_open();
403  }
404  void enable_surround_quote_on_str(bool enable, char quote, const std::string& escape = "&quot;")
405  {
406  surround_quote_on_str = enable;
407  surround_quote = quote;
408  quote_escape = escape;
409  }
410  void set_delimiter(char delimiter_, std::string const & escape_str_)
411  {
412  delimiter = delimiter_;
413  escape_str = escape_str_;
414  }
415  std::string const & get_delimiter() const
416  {
417  return delimiter;
418  }
419  std::string const & get_escape_str() const
420  {
421  return escape_str;
422  }
423  void set_after_newline(bool after_newline_)
424  {
425  after_newline = after_newline_;
426  }
427  bool get_after_newline() const
428  {
429  return after_newline;
430  }
431  std::ofstream& get_ofstream()
432  {
433  return ostm;
434  }
435  void escape_and_output(std::string src)
436  {
437  ostm << ((escape_str.empty()) ? src : replace(src, delimiter, escape_str));
438  }
439  void escape_str_and_output(std::string src)
440  {
441  src = ((escape_str.empty()) ? src : replace(src, delimiter, escape_str));
442  if (surround_quote_on_str)
443  {
444  if (!quote_escape.empty())
445  {
446  src = replace(src, std::string(1, surround_quote), quote_escape);
447  }
448  ostm << surround_quote << src << surround_quote;
449  }
450  else
451  {
452  ostm << src;
453  }
454  }
455  private:
456  std::ofstream ostm;
457  bool after_newline;
458  std::string delimiter;
459  std::string escape_str;
460  bool surround_quote_on_str;
461  char surround_quote;
462  std::string quote_escape;
463  };
464 
465 
466  } // ns csv
467 } // ns mini
468 
469 template<typename T>
471 {
472  std::string str = istm.get_delimited_str();
473 
474 #ifdef USE_BOOST_LEXICAL_CAST
475  try
476  {
477  val = boost::lexical_cast<T>(str);
478  }
479  catch (boost::bad_lexical_cast& e)
480  {
481  throw std::runtime_error(istm.error_line(str).c_str());
482  }
483 #else
484  std::istringstream is(str);
485  is >> val;
486  if (!(bool)is)
487  {
488  throw std::runtime_error(istm.error_line(str).c_str());
489  }
490 #endif
491 
492  return istm;
493 }
494 template<>
495 inline mini::csv::ifstream& operator >> (mini::csv::ifstream& istm, std::string& val)
496 {
497  val = istm.get_delimited_str();
498 
499  return istm;
500 }
501 
502 template<>
504 {
505  istm.set_delimiter(val.get_delimiter(), val.get_escape());
506 
507  return istm;
508 }
509 
510 template<typename T>
512 {
513  if(!ostm.get_after_newline())
514  ostm.get_ofstream() << ostm.get_delimiter();
515 
516  std::ostringstream os_temp;
517 
518  os_temp << val;
519 
520  ostm.escape_and_output(os_temp.str());
521 
522  ostm.set_after_newline(false);
523 
524  return ostm;
525 }
526 
527 template<typename T>
529 {
530  if (!ostm.get_after_newline())
531  ostm.get_ofstream() << ostm.get_delimiter();
532 
533  std::ostringstream os_temp;
534 
535  os_temp << *val;
536 
537  ostm.escape_and_output(os_temp.str());
538 
539  ostm.set_after_newline(false);
540 
541  return ostm;
542 }
543 
544 template<>
545 inline mini::csv::ofstream& operator << (mini::csv::ofstream& ostm, const std::string& val)
546 {
547  if (!ostm.get_after_newline())
548  ostm.get_ofstream() << ostm.get_delimiter();
549 
550  std::string temp = val;
551  ostm.escape_str_and_output(temp);
552 
553  ostm.set_after_newline(false);
554 
555  return ostm;
556 }
557 
558 template<>
560 {
561  ostm.set_delimiter(val.get_delimiter(), val.get_escape());
562 
563  return ostm;
564 }
565 
566 template<>
567 inline mini::csv::ofstream& operator << (mini::csv::ofstream& ostm, const char& val)
568 {
569  if(val==NEWLINE)
570  {
571  ostm.get_ofstream() << NEWLINE;
572 
573  ostm.set_after_newline(true);
574  }
575  else
576  {
577  std::ostringstream os_temp;
578 
579  os_temp << val;
580 
581  ostm.escape_and_output(os_temp.str());
582  }
583 
584  return ostm;
585 }
586 template<>
587 inline mini::csv::ofstream& operator << (mini::csv::ofstream& ostm, const char* val)
588 {
589  const std::string temp = val;
590 
591  ostm << temp;
592 
593  return ostm;
594 }
595 
596 namespace mini
597 {
598  namespace csv
599  {
600 
602  {
603  public:
604  istringstream(const char * text)
605  : str("")
606  , pos(0)
607  , delimiter(",")
608  , unescape_str("##")
609  , trim_quote_on_str(false)
610  , trim_quote('\"')
611  , terminate_on_blank_line(true)
612  , quote_unescape("&quot;")
613  , line_num(0)
614  , token_num(0)
615  {
616  istm.str(text);
617  }
618  void enable_trim_quote_on_str(bool enable, char quote, const std::string& unescape = "&quot;")
619  {
620  trim_quote_on_str = enable;
621  trim_quote = quote;
622  quote_unescape = unescape;
623  }
624  void set_delimiter(char delimiter_, std::string const & unescape_str_)
625  {
626  delimiter = delimiter_;
627  unescape_str = unescape_str_;
628  }
629  std::string const & get_delimiter() const
630  {
631  return delimiter;
632  }
633  std::string const & get_unescape_str() const
634  {
635  return unescape_str;
636  }
637  void skip_line()
638  {
639  std::getline(istm, str);
640  pos = 0;
641  }
642  bool read_line()
643  {
644  this->str = "";
645  while (!istm.eof())
646  {
647  std::getline(istm, this->str);
648  pos = 0;
649 
650  if (this->str.empty())
651  {
652  if (terminate_on_blank_line)
653  break;
654  else
655  continue;
656  }
657 
658  ++line_num;
659  token_num = 0;
660  return true;
661  }
662  return false;
663  }
664  std::string get_delimited_str()
665  {
666  std::string str = "";
667  char ch = '\0';
668  bool within_quote = false;
669  do
670  {
671  if (pos >= this->str.size())
672  {
673  this->str = "";
674 
675  ++token_num;
676  return unescape(str);
677  }
678 
679  ch = this->str[pos];
680  if (trim_quote_on_str)
681  {
682  if (within_quote == false && ch == trim_quote && ((pos > 0 && this->str[pos - 1] == delimiter[0]) || pos == 0))
683  within_quote = true;
684  else if (within_quote && ch == trim_quote)
685  within_quote = false;
686  }
687 
688  ++(pos);
689 
690  if (ch == delimiter[0] && within_quote == false)
691  break;
692  if (ch == '\r' || ch == '\n')
693  break;
694 
695  str += ch;
696  } while (true);
697 
698  ++token_num;
699  return unescape(str);
700  }
701 
702  std::string unescape(std::string & src)
703  {
704  src = unescape_str.empty() ? src : replace(src, unescape_str, delimiter);
705  if (trim_quote_on_str)
706  {
707  std::string s = trim(src, std::string(1, trim_quote));
708  return replace(s, quote_unescape, std::string(1, trim_quote));
709  }
710  return src;
711  }
712 
713  size_t num_of_delimiter() const
714  {
715  if (delimiter.size() == 0)
716  return 0;
717 
718  size_t cnt = 0;
719  if (trim_quote_on_str)
720  {
721  bool inside_quote = false;
722  for (size_t i = 0; i < str.size(); ++i)
723  {
724  if (str[i] == trim_quote)
725  inside_quote = !inside_quote;
726 
727  if (!inside_quote)
728  {
729  if (str[i] == delimiter[0])
730  ++cnt;
731  }
732  }
733  }
734  else
735  {
736  cnt = std::count(str.begin(), str.end(), delimiter[0]);
737  }
738  return cnt;
739  }
740  std::string get_rest_of_line() const
741  {
742  return str.substr(pos);
743  }
744  const std::string& get_line() const
745  {
746  return str;
747  }
748  void enable_terminate_on_blank_line(bool enable)
749  {
750  terminate_on_blank_line = enable;
751  }
752  bool is_terminate_on_blank_line() const
753  {
754  return terminate_on_blank_line;
755  }
756  std::string error_line(const std::string& token)
757  {
758  std::ostringstream is;
759  is << "csv::istringstream conversion error at line no.:" << line_num << ", token position:" << token_num << ", token:" << token;
760  return is.str();
761  }
762 
763  private:
764  std::istringstream istm;
765  std::string str;
766  size_t pos;
767  std::string delimiter;
768  std::string unescape_str;
769  bool trim_quote_on_str;
770  char trim_quote;
771  bool terminate_on_blank_line;
772  std::string quote_unescape;
773  size_t line_num;
774  size_t token_num;
775  };
776 
778  {
779  public:
780 
781  ostringstream()
782  : after_newline(true)
783  , delimiter(",")
784  , escape_str("##")
785  , surround_quote_on_str(false)
786  , surround_quote('\"')
787  , quote_escape("&quot;")
788  {
789  }
790  void enable_surround_quote_on_str(bool enable, char quote, const std::string& escape = "&quot;")
791  {
792  surround_quote_on_str = enable;
793  surround_quote = quote;
794  quote_escape = escape;
795  }
796  void set_delimiter(char delimiter_, std::string const & escape_str_)
797  {
798  delimiter = delimiter_;
799  escape_str = escape_str_;
800  }
801  std::string const & get_delimiter() const
802  {
803  return delimiter;
804  }
805  std::string const & get_escape_str() const
806  {
807  return escape_str;
808  }
809  void set_after_newline(bool after_newline_)
810  {
811  after_newline = after_newline_;
812  }
813  bool get_after_newline() const
814  {
815  return after_newline;
816  }
817  std::ostringstream& get_ostringstream()
818  {
819  return ostm;
820  }
821  std::string get_text()
822  {
823  return ostm.str();
824  }
825  void escape_and_output(std::string src)
826  {
827  ostm << ((escape_str.empty()) ? src : replace(src, delimiter, escape_str));
828  }
829  void escape_str_and_output(std::string src)
830  {
831  src = ((escape_str.empty()) ? src : replace(src, delimiter, escape_str));
832  if (surround_quote_on_str)
833  {
834  if (!quote_escape.empty())
835  {
836  src = replace(src, std::string(1, surround_quote), quote_escape);
837  }
838  ostm << surround_quote << src << surround_quote;
839  }
840  else
841  {
842  ostm << src;
843  }
844  }
845 
846  private:
847  std::ostringstream ostm;
848  bool after_newline;
849  std::string delimiter;
850  std::string escape_str;
851  bool surround_quote_on_str;
852  char surround_quote;
853  std::string quote_escape;
854  };
855 
856 
857  } // ns csv
858 } // ns mini
859 
860 template<typename T>
862 {
863  std::string str = istm.get_delimited_str();
864 
865 #ifdef USE_BOOST_LEXICAL_CAST
866  try
867  {
868  val = boost::lexical_cast<T>(str);
869  }
870  catch (boost::bad_lexical_cast& e)
871  {
872  throw std::runtime_error(istm.error_line(str).c_str());
873  }
874 #else
875  std::istringstream is(str);
876  is >> val;
877  if (!(bool)is)
878  {
879  throw std::runtime_error(istm.error_line(str).c_str());
880  }
881 #endif
882 
883  return istm;
884 }
885 template<>
887 {
888  val = istm.get_delimited_str();
889 
890  return istm;
891 }
892 
893 template<>
895 {
896  istm.set_delimiter(val.get_delimiter(), val.get_escape());
897 
898  return istm;
899 }
900 
901 template<typename T>
903 {
904  if (!ostm.get_after_newline())
905  ostm.get_ostringstream() << ostm.get_delimiter();
906 
907  std::ostringstream os_temp;
908 
909  os_temp << val;
910 
911  ostm.escape_and_output(os_temp.str());
912 
913  ostm.set_after_newline(false);
914 
915  return ostm;
916 }
917 template<typename T>
919 {
920  if (!ostm.get_after_newline())
921  ostm.get_ostringstream() << ostm.get_delimiter();
922 
923  std::ostringstream os_temp;
924 
925  os_temp << *val;
926 
927  ostm.escape_and_output(os_temp.str());
928 
929  ostm.set_after_newline(false);
930 
931  return ostm;
932 }
933 template<>
934 inline mini::csv::ostringstream& operator << (mini::csv::ostringstream& ostm, const std::string& val)
935 {
936  if (!ostm.get_after_newline())
937  ostm.get_ostringstream() << ostm.get_delimiter();
938 
939  std::string temp = val;
940  ostm.escape_str_and_output(temp);
941 
942  ostm.set_after_newline(false);
943 
944  return ostm;
945 }
946 template<>
948 {
949  ostm.set_delimiter(val.get_delimiter(), val.get_escape());
950 
951  return ostm;
952 }
953 
954 template<>
956 {
957  if (val == NEWLINE)
958  {
959  ostm.get_ostringstream() << NEWLINE;
960 
961  ostm.set_after_newline(true);
962  }
963  else
964  {
965  std::ostringstream os_temp;
966 
967  os_temp << val;
968 
969  ostm.escape_and_output(os_temp.str());
970  }
971 
972  return ostm;
973 }
974 template<>
976 {
977  const std::string temp = val;
978 
979  ostm << temp;
980 
981  return ostm;
982 }
983 
984 
985 #endif // MiniCSV_H
std::string trim_left(const std::string &str, const std::string &trimChars)
Definition: minicsv.h:84
#define NEWLINE
Definition: minicsv.h:45
mini::csv::ifstream & operator>>(mini::csv::ifstream &istm, T &val)
Definition: minicsv.h:470
const char delimiter
Definition: minicsv.h:112
Definition: minicsv.h:47
const std::string escape
Definition: minicsv.h:113
sep(const char delimiter_, const std::string &escape_)
Definition: minicsv.h:107
std::string trim_right(const std::string &str, const std::string &trimChars)
Definition: minicsv.h:70
std::string const & replace(std::string &src, std::string const &to_find, std::string const &to_replace)
Definition: minicsv.h:52
const std::string & get_escape() const
Definition: minicsv.h:110
const char get_delimiter() const
Definition: minicsv.h:109
mini::csv::ofstream & operator<<(mini::csv::ofstream &ostm, const T &val)
Definition: minicsv.h:511
std::string trim(const std::string &str, const std::string &trimChars)
Definition: minicsv.h:99


pfuclt_omni_dataset
Author(s):
autogenerated on Tue Jul 4 2017 19:38:38