-
Notifications
You must be signed in to change notification settings - Fork 0
/
csv.h
107 lines (92 loc) · 3.36 KB
/
csv.h
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
// CVS reader
// Part of lvvlib - https://github.com/lvv/lvvlib
// Copyright (c) 2000-2013
// Leonid Volnitsky ([email protected])
#ifndef LVV_CSV_H
#define LVV_CSV_H
// from http://www.daniweb.com/code/snippet217438.html
//
// TOFIX: If the last input line isn't terminated by right recordDelim character last returned record doesn't contain last value.
#include <istream>
#include <string>
#include <vector>
/// <summary>loads a CSV record from the stream is</summary>
/// <remarks>
/// * leading and trailing white space is removed outside of
// quoted sections when trimWhiteSpace is true
/// * line breaks are preserved in quoted sections
/// * quote literals consist of two adjacent quote characters
/// * quote literals must be in quoted sections
/// </remarks>
/// <param name=is>input stream for CSV records</param>
/// <param name=trimWhiteSpace>trims white space on unquoted fields</param>
/// <param name=fieldDelim>field delimiter. defaults to ',' for CSV</param>
/// <param name=recordDelim>record delimiter. defaults to '\n' for CSV</param>
/// <param name=quote>delimiter for quoted fields. defaults to '"'</param>
/// <returns>a list of fields in the record</returns>
namespace lvv {
std::vector <std::string>
csv_get_line( std::istream & is, bool trimWhiteSpace = true, const char fieldDelim = ',', const char recordDelim = '\n', const char quote = '"') {
using namespace std;
vector < string > record; // result record list. default empty
string field; // temporary field construction zone
int start = -1, // start of a quoted section for trimming
end = -1; // end of a quoted section for trimming
char ch;
while (is.get(ch)) {
if (ch == fieldDelim || ch == recordDelim)
// fieldDelim and recordDelim mark the end of a
// field. save the field, reset for the next field,
// and break if there are no more fields
{
if (trimWhiteSpace)
// trim all external white space
// exclude chars between start and end
{
const string wsList = " \t\n\f\v\r";
int ePos, sPos;
// order dependency: right trim before let trim
// left trim will invalidate end's index value
if ((ePos = field.find_last_not_of(wsList)) != string::npos) {
// ePos+1 because find_last_not_of stops on white space
field.erase((end > ePos) ? end : ePos + 1);
}
if ((sPos = field.find_first_not_of(wsList)) != string::npos) {
field.erase(0, (start != -1 && start < sPos) ? start : sPos);
}
// reset the quoted section
start = end = -1;
}
// save the new field and reset the temporary
record.push_back(field);
field.clear();
// exit case 1: !is, managed by loop condition
// exit case 2: recordDelim, managed here
if (ch == recordDelim)
break;
} else if (ch == quote) {
// save the start of the quoted section
start = field.length();
while (is.get(ch)) {
if (ch == '"') {
// consecutive quotes are an escaped quote literal
// only applies in quoted fields
// 'a""b""c' becomes 'abc'
// 'a"""b"""c' becomes 'a"b"c'
// '"a""b""c"' becomes 'a"b"c'
if (is.peek() != '"') {
// save the end of the quoted section
end = field.length();
break;
} else
field.push_back(is.get());
} else
field.push_back(ch);
}
} else
field.push_back(ch);
}
return record;
}
}; // namespace lvv
#endif // LVV_CSV_H