-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathCSVTools.h
More file actions
169 lines (153 loc) · 4.25 KB
/
CSVTools.h
File metadata and controls
169 lines (153 loc) · 4.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/*
Ravel C API. © Ravelation Pty Ltd 2025
*/
#ifndef RAVEL_CSVTOOLS_H
#define RAVEL_CSVTOOLS_H
#include <algorithm>
#include <string>
namespace ravel
{
struct CSVSpec
{
char separator=','; ///< field separator character
char quote='"'; ///< quote character
char escape='\0'; ///< escape character, might be backslash, technically shouldn't be used for CSV
char decSeparator='.'; ///< decimal "point", usually '.' or ','.
};
/// get complete line from input, allowing for quoted linefeed
bool getWholeLine(std::istream& input, std::string& line, const CSVSpec& spec);
/// replace doubled quotes with escaped quotes
void escapeDoubledQuotes(std::string&,const CSVSpec&);
// pinched from boost::escape_list_separator, and modified to not throw
template <class Char,
class Traits = typename std::basic_string<Char>::traits_type >
class EscapedListSeparator {
private:
typedef std::basic_string<Char,Traits> string_type;
struct char_eq {
Char e_;
char_eq(Char e):e_(e) { }
bool operator()(Char c) {
return Traits::eq(e_,c);
}
};
string_type escape_;
string_type c_;
string_type quote_;
bool last_;
bool is_escape(Char e) {
const char_eq f(e);
return std::find_if(escape_.begin(),escape_.end(),f)!=escape_.end();
}
bool is_c(Char e) {
const char_eq f(e);
return std::find_if(c_.begin(),c_.end(),f)!=c_.end();
}
bool is_quote(Char e) {
const char_eq f(e);
return std::find_if(quote_.begin(),quote_.end(),f)!=quote_.end();
}
template <typename iterator, typename Token>
void do_escape(iterator& next,iterator end,Token& tok) {
if (++next >= end)
// don't throw, but pass on verbatim
tok+=escape_.front();
if (Traits::eq(*next,'n')) {
tok+='\n';
return;
}
if (is_quote(*next)) {
tok+=*next;
return;
}
if (is_c(*next)) {
tok+=*next;
return;
}
if (is_escape(*next)) {
tok+=*next;
return;
}
// don't throw, but pass on verbatim
tok+=escape_.front()+*next;
}
public:
explicit EscapedListSeparator(Char e = '\\')
: escape_(1,e), c_(1,','), quote_(1,'\"'), last_(false) { }
EscapedListSeparator(Char e, Char c,Char q = '\"')
: escape_(1,e), c_(1,c), quote_(1,q), last_(false) { }
void reset() {last_=false;}
template <typename InputIterator, typename Token>
bool operator()(InputIterator& next,InputIterator end,Token& tok) {
bool bInQuote = false;
tok = Token();
if (next >= end) {
next=end; // reset next in case it has adavanced beyond
if (last_) {
last_ = false;
return true;
}
return false;
}
last_ = false;
while (next < end) {
if (is_escape(*next)) {
do_escape(next,end,tok);
}
else if (is_c(*next)) {
if (!bInQuote) {
// If we are not in quote, then we are done
++next;
// The last character was a c, that means there is
// 1 more blank field
last_ = true;
return true;
}
tok+=*next;
}
else if (is_quote(*next)) {
bInQuote=!bInQuote;
}
else {
tok += *next;
}
++next;
}
return true;
}
};
using Parser=EscapedListSeparator<char>;
struct SpaceSeparatorParser
{
char escape, quote;
SpaceSeparatorParser(char escape='\\', char sep=' ', char quote='"'):
escape(escape), quote(quote) {}
template <class I>
bool operator()(I& next, I end, std::string& tok)
{
tok.clear();
bool quoted=false;
while (next!=end)
{
if (*next==escape)
tok+=*(++next);
else if (*next==quote)
quoted=!quoted;
else if (!quoted && isspace(*next))
{
while (isspace(*next)) ++next;
return true;
}
else
tok+=*next;
++next;
}
return !tok.empty();
}
void reset() {}
};
}
#if defined(CLASSDESC) || defined(ECOLAB_LIB)
#include "CSVTools.cd"
#endif
#endif