Electroneum
minicsv.h
Go to the documentation of this file.
1 // The MIT License (MIT)
2 // Minimalistic CSV Streams 1.6
3 // Copyright (C) 2014, 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 
24 //#define USE_BOOST_LEXICAL_CAST
25 
26 #ifndef MiniCSV_H
27  #define MiniCSV_H
28 
29 #include <string>
30 #include <sstream>
31 #include <fstream>
32 
33 #ifdef USE_BOOST_LEXICAL_CAST
34 # include <boost/lexical_cast.hpp>
35 #endif
36 
37 #define NEWLINE '\n'
38 
39 namespace csv
40 {
41  inline std::string const & replace(std::string & src, std::string const & to_find, std::string const & to_replace)
42  {
43  size_t pos = 0;
44  while (std::string::npos != pos)
45  {
46  pos = src.find(to_find, pos);
47 
48  if (std::string::npos != pos)
49  {
50  src.erase(pos, to_find.size());
51  src.insert(pos, to_replace);
52  pos += to_replace.size();
53  }
54  }
55 
56  return src;
57  }
58 
59  inline std::string trim_right(const std::string& str, const std::string& trimChars)
60  {
61  std::string result = "";
62  size_t endpos = str.find_last_not_of(trimChars);
63  if (std::string::npos != endpos)
64  {
65  result = str.substr(0, endpos + 1);
66  }
67  else
68  result = str;
69 
70  return result;
71  }
72 
73  inline std::string trim_left(const std::string& str, const std::string& trimChars)
74  {
75  std::string result = "";
76 
77  size_t startpos = str.find_first_not_of(trimChars);
78  if (std::string::npos != startpos)
79  {
80  result = str.substr(startpos);
81  }
82  else
83  result = str;
84 
85  return result;
86  }
87 
88  inline std::string trim(const std::string& str, const std::string& trimChars)
89  {
90  return trim_left(trim_right(str, trimChars), trimChars);
91  }
92 
93  class ifstream
94  {
95  public:
96  ifstream() : str(""), pos(0), delimiter(","), unescape_str("##"), trim_quote_on_str(false), trim_quote('\"'), terminate_on_blank_line(true)
97  {
98  }
99  ifstream(const char * file)
100  {
101  open(file);
102  }
103  void open(const char * file)
104  {
105  init();
106  istm.open(file, std::ios_base::in);
107  }
108  void init()
109  {
110  str = "";
111  pos = 0;
112  delimiter = ',';
113  unescape_str = "##";
114  trim_quote_on_str = false;
115  trim_quote = '\"';
116  terminate_on_blank_line = true;
117  }
118  void close()
119  {
120  istm.close();
121  }
122  bool is_open()
123  {
124  return istm.is_open();
125  }
126  void enable_trim_quote_on_str(bool enable, char quote)
127  {
128  trim_quote_on_str = enable;
129  trim_quote = quote;
130  }
131  // eof is replaced by read_line
132  //bool eof() const
133  void set_delimiter(char delimiter_, std::string const & unescape_str_)
134  {
135  delimiter = delimiter_;
136  unescape_str = unescape_str_;
137  }
138  std::string const & get_delimiter() const
139  {
140  return delimiter;
141  }
142  std::string const & get_unescape_str() const
143  {
144  return unescape_str;
145  }
146  void skip_line()
147  {
148  if(!istm.eof())
149  {
150  std::getline(istm, str);
151  pos = 0;
152  }
153  }
154  bool read_line()
155  {
156  this->str = "";
157  while(!istm.eof())
158  {
159  std::getline(istm, this->str);
160  pos = 0;
161 
162  if (this->str.empty())
163  {
164  if (terminate_on_blank_line)
165  break;
166  else
167  continue;
168  }
169 
170  return true;
171  }
172  return false;
173  }
174  std::string get_delimited_str()
175  {
176  std::string str = "";
177  char ch = '\0';
178  bool within_quote = false;
179  do
180  {
181  if(pos>=this->str.size())
182  {
183  this->str = "";
184 
185  return unescape(str);
186  }
187 
188  ch = this->str[pos];
189  if (trim_quote_on_str)
190  {
191  if (within_quote == false && ch == trim_quote && ((pos > 0 && this->str[pos - 1] == delimiter[0]) || pos == 0))
192  within_quote = true;
193  else if (within_quote && ch == trim_quote)
194  within_quote = false;
195  }
196 
197  ++(pos);
198 
199  if (ch == delimiter[0] && within_quote == false)
200  break;
201  if (ch == '\r' || ch == '\n')
202  break;
203 
204  str += ch;
205  }
206  while(true);
207 
208  return unescape(str);
209  }
210  std::string unescape(std::string & src)
211  {
212  src = unescape_str.empty() ? src : replace(src, unescape_str, delimiter);
213  return trim_quote_on_str ? trim(src, std::string(1, trim_quote)) : src;
214  }
215  size_t num_of_delimiter() const
216  {
217  if (delimiter.size() == 0)
218  return 0;
219 
220  size_t cnt = 0;
221  for (size_t i = 0; i < str.size(); ++i)
222  {
223  if (str[i] == delimiter[0])
224  ++cnt;
225  }
226  return cnt;
227  }
228  std::string get_rest_of_line() const
229  {
230  return str.substr(pos);
231  }
232  const std::string& get_line() const
233  {
234  return str;
235  }
236  void enable_terminate_on_blank_line(bool enable)
237  {
238  terminate_on_blank_line = enable;
239  }
240  bool is_terminate_on_blank_line() const
241  {
242  return terminate_on_blank_line;
243  }
244 
245  private:
246  std::ifstream istm;
247  std::string str;
248  size_t pos;
249  std::string delimiter;
250  std::string unescape_str;
251  bool trim_quote_on_str;
252  char trim_quote;
253  bool terminate_on_blank_line;
254  };
255 
256  class ofstream
257  {
258  public:
259 
260  ofstream() : after_newline(true), delimiter(","), escape_str("##"), surround_quote_on_str(false), surround_quote('\"')
261  {
262  }
263  ofstream(const char * file)
264  {
265  open(file);
266  }
267  void open(const char * file)
268  {
269  init();
270  ostm.open(file, std::ios_base::out);
271  }
272  void init()
273  {
274  after_newline = true;
275  delimiter = ',';
276  escape_str = "##";
277  surround_quote_on_str = false;
278  surround_quote = '\"';
279  }
280  void flush()
281  {
282  ostm.flush();
283  }
284  void close()
285  {
286  ostm.close();
287  }
288  bool is_open()
289  {
290  return ostm.is_open();
291  }
292  void enable_surround_quote_on_str(bool enable, char quote)
293  {
294  surround_quote_on_str = enable;
295  surround_quote = quote;
296  }
297  void set_delimiter(char delimiter_, std::string const & escape_str_)
298  {
299  delimiter = delimiter_;
300  escape_str = escape_str_;
301  }
302  std::string const & get_delimiter() const
303  {
304  return delimiter;
305  }
306  std::string const & get_escape_str() const
307  {
308  return escape_str;
309  }
310  void set_after_newline(bool after_newline_)
311  {
312  after_newline = after_newline_;
313  }
314  bool get_after_newline() const
315  {
316  return after_newline;
317  }
318  std::ofstream& get_ofstream()
319  {
320  return ostm;
321  }
322  void escape_and_output(std::string src)
323  {
324  ostm << ((escape_str.empty()) ? src : replace(src, delimiter, escape_str));
325  }
326  void escape_str_and_output(std::string src)
327  {
328  src = ((escape_str.empty()) ? src : replace(src, delimiter, escape_str));
329  if (surround_quote_on_str)
330  {
331  ostm << surround_quote << src << surround_quote;
332  }
333  else
334  {
335  ostm << src;
336  }
337  }
338  private:
339  std::ofstream ostm;
340  bool after_newline;
341  std::string delimiter;
342  std::string escape_str;
343  bool surround_quote_on_str;
344  char surround_quote;
345  };
346 
347 
348 } // ns csv
349 
350 template<typename T>
352 {
353  std::string str = istm.get_delimited_str();
354 
355 #ifdef USE_BOOST_LEXICAL_CAST
356  val = boost::lexical_cast<T>(str);
357 #else
358  std::istringstream is(str);
359  is >> val;
360 #endif
361 
362  return istm;
363 }
364 template<>
365 inline csv::ifstream& operator >> (csv::ifstream& istm, std::string& val)
366 {
367  val = istm.get_delimited_str();
368 
369  return istm;
370 }
371 
372 template<typename T>
374 {
375  if(!ostm.get_after_newline())
376  ostm.get_ofstream() << ostm.get_delimiter();
377 
378  std::ostringstream os_temp;
379 
380  os_temp << val;
381 
382  ostm.escape_and_output(os_temp.str());
383 
384  ostm.set_after_newline(false);
385 
386  return ostm;
387 }
388 
389 template<typename T>
391 {
392  if (!ostm.get_after_newline())
393  ostm.get_ofstream() << ostm.get_delimiter();
394 
395  std::ostringstream os_temp;
396 
397  os_temp << *val;
398 
399  ostm.escape_and_output(os_temp.str());
400 
401  ostm.set_after_newline(false);
402 
403  return ostm;
404 }
405 
406 template<>
407 inline csv::ofstream& operator << (csv::ofstream& ostm, const std::string& val)
408 {
409  if (!ostm.get_after_newline())
410  ostm.get_ofstream() << ostm.get_delimiter();
411 
412  std::string temp = val;
413  ostm.escape_str_and_output(temp);
414 
415  ostm.set_after_newline(false);
416 
417  return ostm;
418 }
419 template<>
420 inline csv::ofstream& operator << (csv::ofstream& ostm, const char& val)
421 {
422  if(val==NEWLINE)
423  {
424  ostm.get_ofstream() << NEWLINE;
425 
426  ostm.set_after_newline(true);
427  }
428  else
429  {
430  std::ostringstream os_temp;
431 
432  os_temp << val;
433 
434  ostm.escape_and_output(os_temp.str());
435  }
436 
437  return ostm;
438 }
439 template<>
440 inline csv::ofstream& operator << (csv::ofstream& ostm, const char* val)
441 {
442  const std::string temp = val;
443 
444  ostm << temp;
445 
446  return ostm;
447 }
448 
449 namespace csv
450 {
451 
453 {
454 public:
455  istringstream(const char * text)
456  : str("")
457  , pos(0)
458  , delimiter(",")
459  , unescape_str("##")
460  , trim_quote_on_str(false)
461  , trim_quote('\"')
462  , terminate_on_blank_line(true)
463  {
464  istm.str(text);
465  }
466  void enable_trim_quote_on_str(bool enable, char quote)
467  {
468  trim_quote_on_str = enable;
469  trim_quote = quote;
470  }
471  void set_delimiter(char delimiter_, std::string const & unescape_str_)
472  {
473  delimiter = delimiter_;
474  unescape_str = unescape_str_;
475  }
476  std::string const & get_delimiter() const
477  {
478  return delimiter;
479  }
480  std::string const & get_unescape_str() const
481  {
482  return unescape_str;
483  }
484  void skip_line()
485  {
486  std::getline(istm, str);
487  pos = 0;
488  }
489  bool read_line()
490  {
491  this->str = "";
492  while (!istm.eof())
493  {
494  std::getline(istm, this->str);
495  pos = 0;
496 
497  if (this->str.empty())
498  {
499  if (terminate_on_blank_line)
500  break;
501  else
502  continue;
503  }
504 
505  return true;
506  }
507  return false;
508  return false;
509  }
510  std::string get_delimited_str()
511  {
512  std::string str = "";
513  char ch = '\0';
514  bool within_quote = false;
515  do
516  {
517  if (pos >= this->str.size())
518  {
519  this->str = "";
520 
521  return unescape(str);
522  }
523 
524  ch = this->str[pos];
525  if (trim_quote_on_str)
526  {
527  if (within_quote == false && ch == trim_quote && ((pos > 0 && this->str[pos - 1] == delimiter[0]) || pos == 0))
528  within_quote = true;
529  else if (within_quote && ch == trim_quote)
530  within_quote = false;
531  }
532 
533  ++(pos);
534 
535  if (ch == delimiter[0] && within_quote == false)
536  break;
537  if (ch == '\r' || ch == '\n')
538  break;
539 
540  str += ch;
541  } while (true);
542 
543  return unescape(str);
544  }
545 
546  std::string unescape(std::string & src)
547  {
548  src = unescape_str.empty() ? src : replace(src, unescape_str, delimiter);
549  return trim_quote_on_str ? trim(src, std::string(1, trim_quote)) : src;
550  }
551 
552  size_t num_of_delimiter() const
553  {
554  if (delimiter.size() == 0)
555  return 0;
556 
557  size_t cnt = 0;
558  for (size_t i = 0; i < str.size(); ++i)
559  {
560  if (str[i] == delimiter[0])
561  ++cnt;
562  }
563  return cnt;
564  }
565  std::string get_rest_of_line() const
566  {
567  return str.substr(pos);
568  }
569  const std::string& get_line() const
570  {
571  return str;
572  }
573  void enable_terminate_on_blank_line(bool enable)
574  {
575  terminate_on_blank_line = enable;
576  }
577  bool is_terminate_on_blank_line() const
578  {
579  return terminate_on_blank_line;
580  }
581 
582 private:
583  std::istringstream istm;
584  std::string str;
585  size_t pos;
586  std::string delimiter;
587  std::string unescape_str;
588  bool trim_quote_on_str;
589  char trim_quote;
590  bool terminate_on_blank_line;
591 };
592 
594 {
595 public:
596 
597  ostringstream() : after_newline(true), delimiter(","), escape_str("##"), surround_quote_on_str(false), surround_quote('\"')
598  {
599  }
600  void enable_surround_quote_on_str(bool enable, char quote)
601  {
602  surround_quote_on_str = enable;
603  surround_quote = quote;
604  }
605  void set_delimiter(char delimiter_, std::string const & escape_str_)
606  {
607  delimiter = delimiter_;
608  escape_str = escape_str_;
609  }
610  std::string const & get_delimiter() const
611  {
612  return delimiter;
613  }
614  std::string const & get_escape_str() const
615  {
616  return escape_str;
617  }
618  void set_after_newline(bool after_newline_)
619  {
620  after_newline = after_newline_;
621  }
622  bool get_after_newline() const
623  {
624  return after_newline;
625  }
626  std::ostringstream& get_ostringstream()
627  {
628  return ostm;
629  }
630  std::string get_text()
631  {
632  return ostm.str();
633  }
634  void escape_and_output(std::string src)
635  {
636  ostm << ((escape_str.empty()) ? src : replace(src, delimiter, escape_str));
637  }
638  void escape_str_and_output(std::string src)
639  {
640  src = ((escape_str.empty()) ? src : replace(src, delimiter, escape_str));
641  if (surround_quote_on_str)
642  {
643  ostm << surround_quote << src << surround_quote;
644  }
645  else
646  {
647  ostm << src;
648  }
649  }
650 
651 private:
652  std::ostringstream ostm;
653  bool after_newline;
654  std::string delimiter;
655  std::string escape_str;
656  bool surround_quote_on_str;
657  char surround_quote;
658 };
659 
660 
661 } // ns csv
662 
663 template<typename T>
665 {
666  std::string str = istm.get_delimited_str();
667 
668 #ifdef USE_BOOST_LEXICAL_CAST
669  val = boost::lexical_cast<T>(str);
670 #else
671  std::istringstream is(str);
672  is >> val;
673 #endif
674 
675  return istm;
676 }
677 template<>
678 inline csv::istringstream& operator >> (csv::istringstream& istm, std::string& val)
679 {
680  val = istm.get_delimited_str();
681 
682  return istm;
683 }
684 
685 template<typename T>
687 {
688  if (!ostm.get_after_newline())
689  ostm.get_ostringstream() << ostm.get_delimiter();
690 
691  std::ostringstream os_temp;
692 
693  os_temp << val;
694 
695  ostm.escape_and_output(os_temp.str());
696 
697  ostm.set_after_newline(false);
698 
699  return ostm;
700 }
701 template<typename T>
703 {
704  if (!ostm.get_after_newline())
705  ostm.get_ostringstream() << ostm.get_delimiter();
706 
707  std::ostringstream os_temp;
708 
709  os_temp << val;
710 
711  ostm.escape_and_output(os_temp.str());
712 
713  ostm.set_after_newline(false);
714 
715  return ostm;
716 }
717 template<>
718 inline csv::ostringstream& operator << (csv::ostringstream& ostm, const std::string& val)
719 {
720  if (!ostm.get_after_newline())
721  ostm.get_ostringstream() << ostm.get_delimiter();
722 
723  std::string temp = val;
724  ostm.escape_str_and_output(temp);
725 
726  ostm.set_after_newline(false);
727 
728  return ostm;
729 }
730 
731 template<>
732 inline csv::ostringstream& operator << (csv::ostringstream& ostm, const char& val)
733 {
734  if (val == NEWLINE)
735  {
736  ostm.get_ostringstream() << NEWLINE;
737 
738  ostm.set_after_newline(true);
739  }
740  else
741  {
742  std::ostringstream os_temp;
743 
744  os_temp << val;
745 
746  ostm.escape_and_output(os_temp.str());
747  }
748 
749  return ostm;
750 }
751 template<>
752 inline csv::ostringstream& operator << (csv::ostringstream& ostm, const char* val)
753 {
754  const std::string temp = val;
755 
756  ostm << temp;
757 
758  return ostm;
759 }
760 
761 
762 #endif // MiniCSV_H
Definition: minicsv.h:256
const uint32_t T[512]
Definition: groestl_tables.h:34
Definition: minicsv.h:593
std::string trim(const std::string &str, const std::string &trimChars)
Definition: minicsv.h:88
#define NEWLINE
Definition: minicsv.h:37
Definition: minicsv.h:93
std::string trim_left(const std::string &str, const std::string &trimChars)
Definition: minicsv.h:73
csv::ifstream & operator>>(csv::ifstream &istm, T &val)
Definition: minicsv.h:351
Definition: minicsv.h:452
Definition: minicsv.h:39
std::string const & replace(std::string &src, std::string const &to_find, std::string const &to_replace)
Definition: minicsv.h:41
std::string trim_right(const std::string &str, const std::string &trimChars)
Definition: minicsv.h:59
csv::ofstream & operator<<(csv::ofstream &ostm, const T &val)
Definition: minicsv.h:373