25 #ifndef INCLUDED_CSVTools_h_GUID_82FA298C_196A_46AA_B2D6_059F2A035687 26 #define INCLUDED_CSVTools_h_GUID_82FA298C_196A_46AA_B2D6_059F2A035687 46 static const char COMMA_CHAR =
',';
48 static const char DOUBLEQUOTE_CHAR =
'"';
50 inline std::string getCleanLine(std::istream &is) {
52 std::getline(is, ret);
53 while (!ret.empty() && (ret.back() ==
'\n' || ret.back() ==
'\r')) {
59 namespace string_fields {
61 inline std::size_t getBeginningOfField(std::string
const &line,
67 for (std::size_t i = 0; i < field && pos != std::string::npos; ++i) {
68 pos = line.find(COMMA_CHAR, pos + 1);
70 if (pos != std::string::npos) {
71 if (pos + 1 < line.size()) {
78 pos = std::string::npos;
88 #define CSV_VERIFY(X, MSG) \ 91 throw std::logic_error(MSG); \ 95 #define CSV_VERIFY(X, MSG) 100 using iterator = std::string::const_iterator;
101 StringField(std::string
const &line,
const std::size_t b,
103 : line_(line), b_(b), e_(e), ve_(virtualEndPos(line_, e_)) {
109 : line_(other.line_), b_(b), e_(e_), ve_(virtualEndPos(line_, e_)) {
124 std::size_t
endPos()
const {
return e_; }
127 std::size_t
realLength()
const {
return virtualEndPos() - b_; }
132 return (e_ == std::string::npos) ? std::string::npos : e_ - b_;
136 bool empty()
const {
return beginPos() == virtualEndPos(); }
139 std::string
const &
getLine()
const {
return line_; }
143 return line_.substr(beginPos(), lengthForSubstr());
147 iterator
begin()
const {
return getIteratorAt(beginPos()); }
151 if (e_ == std::string::npos) {
154 return getIteratorAt(endPos());
160 throw std::out_of_range(
161 "can't get front element of an empty string field");
163 return line_[beginPos()];
168 throw std::out_of_range(
169 "can't get back element of an empty string field");
171 return line_[virtualEndPos() - 1];
177 if (realLength() < 2) {
181 if (front() != DOUBLEQUOTE_CHAR || back() != DOUBLEQUOTE_CHAR) {
185 auto newB = beginPos() + 1;
186 auto newE = virtualEndPos() - 1;
198 iterator getIteratorAt(
const std::size_t pos)
const {
199 auto it = line_.cbegin();
200 std::advance(it, pos);
203 static std::size_t virtualEndPos(std::string
const &line,
204 const std::size_t e) {
205 return (e == std::string::npos) ? line.size() : e;
207 void checkInvariants()
const {
208 assert((e_ == std::string::npos || e_ < line_.size()) &&
209 "past the end position must be npos or a valid position");
210 CSV_VERIFY((e_ == std::string::npos || e_ < line_.size()),
211 "past the end position must be npos or a valid position");
212 CSV_VERIFY((b_ < line_.size()),
213 "Begin position must be a valid position");
214 CSV_VERIFY((e_ == std::string::npos || b_ < e_),
215 "Begin position must be strictly before past the end.");
216 CSV_VERIFY((b_ < ve_),
"Begin position must be strictly before the " 217 "virtual past the end.");
219 CSV_VERIFY((e_ == std::string::npos || line_[e_] == COMMA_CHAR),
221 "past the end position must be npos or hold a delimiter.");
224 std::string
const &line_;
225 const std::size_t b_;
226 const std::size_t e_;
227 const std::size_t ve_;
232 template <
typename T>
233 inline bool getField(
StringField const &field,
T &output) {
235 return static_cast<bool>(iss_ >> output);
238 template <
typename T>
239 inline std::pair<bool, T> getFieldAs(
StringField const &field) {
242 auto success =
static_cast<bool>(iss_ >> ret);
243 return std::make_pair(success, ret);
247 std::istringstream iss_;
253 template <
typename F>
255 std::size_t numFields = std::string::npos,
256 std::size_t first = 0) {
258 std::size_t b = string_fields::getBeginningOfField(line, first);
262 bool keepGoing =
true;
263 const auto n = line.size();
266 for (std::size_t i = 0; i < numFields && keepGoing && b < n; ++i) {
267 e = line.find(COMMA_CHAR, b);
268 keepGoing = fieldFunc(line, b, e);
269 if (e == std::string::npos) {
278 inline std::vector<std::string>
279 getFields(std::string
const &line, std::size_t numFields = std::string::npos,
280 std::size_t first = 0) {
281 std::vector<std::string> ret;
282 auto fieldFunc = [&](std::string
const &line, std::size_t beginPos,
283 std::size_t endPos) {
284 bool lambdaRet =
true;
286 if (endPos == std::string::npos) {
288 len = std::string::npos;
292 len = endPos - beginPos;
294 ret.emplace_back(line.substr(beginPos, len));
303 if (field.size() > 1 && field.front() == DOUBLEQUOTE_CHAR &&
304 field.back() == DOUBLEQUOTE_CHAR) {
312 inline void stripQuotes(std::vector<std::string> &fields) {
313 for (
auto &field : fields) {
319 #endif // INCLUDED_CSVTools_h_GUID_82FA298C_196A_46AA_B2D6_059F2A035687