├── files
├── readme.csv
├── simple.csv
└── wiki.csv
├── CMakeLists.txt
├── LICENSE
├── README.md
├── CSVparser.hpp
└── CSVparser.cpp
/files/readme.csv:
--------------------------------------------------------------------------------
1 | Year,Make,Model
2 | 1997,Ford,E350
3 | 2000,Mercury,Cougar
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | project(csv)
2 |
3 | add_library(csv-parser
4 | CSVparser.cpp
5 | CSVparser.hpp
6 | )
--------------------------------------------------------------------------------
/files/simple.csv:
--------------------------------------------------------------------------------
1 | Year,Make,Model,Price
2 | 1997,Ford,E350,3000.00
3 | 1999,Chevy,4900.00
4 | 1999,Chevy,5000.00
5 | 1996,Jeep,4799.00
--------------------------------------------------------------------------------
/files/wiki.csv:
--------------------------------------------------------------------------------
1 | Year,Make,Model,Description,Price
2 | 1997,Ford,E350,"ac, abs, moon",3000.00
3 | 1999,Chevy,"Venture ""Extended Edition""","",4900.00
4 | 1999,Chevy,"Venture ""Extended Edition, Very Large""",,5000.00
5 | 1996,Jeep,Grand Cherokee,"MUST SELL! air, moon roof, loaded",4799.00
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Romain Sylvian
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | CSVparser
2 | =========
3 |
4 | CSVparser intends to be a simple C++ parser for the CSV file format.
5 |
6 | What is a CSV file ?
7 | --------------------
8 |
9 | CSV is a common, relatively simple file format that is widely supported by consumer, business, and scientific applications. Among its most common uses is moving tabular data between programs that natively operate on incompatible (often proprietary and/or undocumented) formats. This works because so many programs support some variation of CSV at least as an alternative import/export format.
10 |
11 | Compilation
12 | -----------
13 |
14 | ```bash
15 | g++ CSVparser.cpp -std=c++0x
16 | ```
17 |
18 | Usage
19 | -----
20 |
21 | The following example shows how to make a simple usage of CSVparser.
22 | Assuming a common CSV file :
23 |
24 | ```
25 | Year,Make,Model
26 | 1997,Ford,E350
27 | 2000,Mercury,Cougar
28 | ```
29 |
30 | ```c++
31 | #include
32 | #include "CSVparser.hpp"
33 |
34 | int main(int argc, char **argv)
35 | {
36 | try
37 | {
38 | csv::Parser file = csv::Parser("files/readme.csv");
39 |
40 | std::cout << file[0][0] << std::endl; // display : 1997
41 | std::cout << file[0] << std::endl; // display : 1997 | Ford | E350
42 |
43 | std::cout << file[1]["Model"] << std::endl; // display : Cougar
44 |
45 | std::cout << file.rowCount() << std::endl; // display : 2
46 | std::cout << file.columnCount() << std::endl; // display : 3
47 |
48 | std::cout << file.getHeaderElement(2) << std::endl; // display : Model
49 | }
50 | catch (csv::Error &e)
51 | {
52 | std::cerr << e.what() << std::endl;
53 | }
54 | return 0;
55 | }
56 | ```
--------------------------------------------------------------------------------
/CSVparser.hpp:
--------------------------------------------------------------------------------
1 | #ifndef _CSVPARSER_HPP_
2 | # define _CSVPARSER_HPP_
3 |
4 | # include
5 | # include
6 | # include
7 | # include
8 | # include
9 |
10 | namespace csv
11 | {
12 | class Error : public std::runtime_error
13 | {
14 |
15 | public:
16 | Error(const std::string &msg):
17 | std::runtime_error(std::string("CSVparser : ").append(msg))
18 | {
19 | }
20 | };
21 |
22 | class Row
23 | {
24 | public:
25 | Row(const std::vector &);
26 | ~Row(void);
27 |
28 | public:
29 | unsigned int size(void) const;
30 | void push(const std::string &);
31 | bool set(const std::string &, const std::string &);
32 |
33 | private:
34 | const std::vector _header;
35 | std::vector _values;
36 |
37 | public:
38 |
39 | template
40 | const T getValue(unsigned int pos) const
41 | {
42 | if (pos < _values.size())
43 | {
44 | T res;
45 | std::stringstream ss;
46 | ss << _values[pos];
47 | ss >> res;
48 | return res;
49 | }
50 | throw Error("can't return this value (doesn't exist)");
51 | }
52 | const std::string operator[](unsigned int) const;
53 | const std::string operator[](const std::string &valueName) const;
54 | friend std::ostream& operator<<(std::ostream& os, const Row &row);
55 | friend std::ofstream& operator<<(std::ofstream& os, const Row &row);
56 | };
57 |
58 | enum DataType {
59 | eFILE = 0,
60 | ePURE = 1
61 | };
62 |
63 | class Parser
64 | {
65 |
66 | public:
67 | Parser(const std::string &, const DataType &type = eFILE, char sep = ',');
68 | ~Parser(void);
69 |
70 | public:
71 | Row &getRow(unsigned int row) const;
72 | unsigned int rowCount(void) const;
73 | unsigned int columnCount(void) const;
74 | std::vector getHeader(void) const;
75 | const std::string getHeaderElement(unsigned int pos) const;
76 | const std::string &getFileName(void) const;
77 |
78 | public:
79 | bool deleteRow(unsigned int row);
80 | bool addRow(unsigned int pos, const std::vector &);
81 | void sync(void) const;
82 |
83 | protected:
84 | void parseHeader(void);
85 | void parseContent(void);
86 |
87 | private:
88 | std::string _file;
89 | const DataType _type;
90 | const char _sep;
91 | std::vector _originalFile;
92 | std::vector _header;
93 | std::vector _content;
94 |
95 | public:
96 | Row &operator[](unsigned int row) const;
97 | };
98 | }
99 |
100 | #endif /*!_CSVPARSER_HPP_*/
101 |
--------------------------------------------------------------------------------
/CSVparser.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include "CSVparser.hpp"
5 |
6 | namespace csv {
7 |
8 | Parser::Parser(const std::string &data, const DataType &type, char sep)
9 | : _type(type), _sep(sep)
10 | {
11 | std::string line;
12 | if (type == eFILE)
13 | {
14 | _file = data;
15 | std::ifstream ifile(_file.c_str());
16 | if (ifile.is_open())
17 | {
18 | while (ifile.good())
19 | {
20 | getline(ifile, line);
21 | if (line != "")
22 | _originalFile.push_back(line);
23 | }
24 | ifile.close();
25 |
26 | if (_originalFile.size() == 0)
27 | throw Error(std::string("No Data in ").append(_file));
28 |
29 | parseHeader();
30 | parseContent();
31 | }
32 | else
33 | throw Error(std::string("Failed to open ").append(_file));
34 | }
35 | else
36 | {
37 | std::istringstream stream(data);
38 | while (std::getline(stream, line))
39 | if (line != "")
40 | _originalFile.push_back(line);
41 | if (_originalFile.size() == 0)
42 | throw Error(std::string("No Data in pure content"));
43 |
44 | parseHeader();
45 | parseContent();
46 | }
47 | }
48 |
49 | Parser::~Parser(void)
50 | {
51 | std::vector::iterator it;
52 |
53 | for (it = _content.begin(); it != _content.end(); it++)
54 | delete *it;
55 | }
56 |
57 | void Parser::parseHeader(void)
58 | {
59 | std::stringstream ss(_originalFile[0]);
60 | std::string item;
61 |
62 | while (std::getline(ss, item, _sep))
63 | _header.push_back(item);
64 | }
65 |
66 | void Parser::parseContent(void)
67 | {
68 | std::vector::iterator it;
69 |
70 | it = _originalFile.begin();
71 | it++; // skip header
72 |
73 | for (; it != _originalFile.end(); it++)
74 | {
75 | bool quoted = false;
76 | int tokenStart = 0;
77 | unsigned int i = 0;
78 |
79 | Row *row = new Row(_header);
80 |
81 | for (; i != it->length(); i++)
82 | {
83 | if (it->at(i) == '"')
84 | quoted = ((quoted) ? (false) : (true));
85 | else if (it->at(i) == ',' && !quoted)
86 | {
87 | row->push(it->substr(tokenStart, i - tokenStart));
88 | tokenStart = i + 1;
89 | }
90 | }
91 |
92 | //end
93 | row->push(it->substr(tokenStart, it->length() - tokenStart));
94 |
95 | // if value(s) missing
96 | if (row->size() != _header.size())
97 | throw Error("corrupted data !");
98 | _content.push_back(row);
99 | }
100 | }
101 |
102 | Row &Parser::getRow(unsigned int rowPosition) const
103 | {
104 | if (rowPosition < _content.size())
105 | return *(_content[rowPosition]);
106 | throw Error("can't return this row (doesn't exist)");
107 | }
108 |
109 | Row &Parser::operator[](unsigned int rowPosition) const
110 | {
111 | return Parser::getRow(rowPosition);
112 | }
113 |
114 | unsigned int Parser::rowCount(void) const
115 | {
116 | return _content.size();
117 | }
118 |
119 | unsigned int Parser::columnCount(void) const
120 | {
121 | return _header.size();
122 | }
123 |
124 | std::vector Parser::getHeader(void) const
125 | {
126 | return _header;
127 | }
128 |
129 | const std::string Parser::getHeaderElement(unsigned int pos) const
130 | {
131 | if (pos >= _header.size())
132 | throw Error("can't return this header (doesn't exist)");
133 | return _header[pos];
134 | }
135 |
136 | bool Parser::deleteRow(unsigned int pos)
137 | {
138 | if (pos < _content.size())
139 | {
140 | delete *(_content.begin() + pos);
141 | _content.erase(_content.begin() + pos);
142 | return true;
143 | }
144 | return false;
145 | }
146 |
147 | bool Parser::addRow(unsigned int pos, const std::vector &r)
148 | {
149 | Row *row = new Row(_header);
150 |
151 | for (auto it = r.begin(); it != r.end(); it++)
152 | row->push(*it);
153 |
154 | if (pos <= _content.size())
155 | {
156 | _content.insert(_content.begin() + pos, row);
157 | return true;
158 | }
159 | return false;
160 | }
161 |
162 | void Parser::sync(void) const
163 | {
164 | if (_type == DataType::eFILE)
165 | {
166 | std::ofstream f;
167 | f.open(_file, std::ios::out | std::ios::trunc);
168 |
169 | // header
170 | unsigned int i = 0;
171 | for (auto it = _header.begin(); it != _header.end(); it++)
172 | {
173 | f << *it;
174 | if (i < _header.size() - 1)
175 | f << ",";
176 | else
177 | f << std::endl;
178 | i++;
179 | }
180 |
181 | for (auto it = _content.begin(); it != _content.end(); it++)
182 | f << **it << std::endl;
183 | f.close();
184 | }
185 | }
186 |
187 | const std::string &Parser::getFileName(void) const
188 | {
189 | return _file;
190 | }
191 |
192 | /*
193 | ** ROW
194 | */
195 |
196 | Row::Row(const std::vector &header)
197 | : _header(header) {}
198 |
199 | Row::~Row(void) {}
200 |
201 | unsigned int Row::size(void) const
202 | {
203 | return _values.size();
204 | }
205 |
206 | void Row::push(const std::string &value)
207 | {
208 | _values.push_back(value);
209 | }
210 |
211 | bool Row::set(const std::string &key, const std::string &value)
212 | {
213 | std::vector::const_iterator it;
214 | int pos = 0;
215 |
216 | for (it = _header.begin(); it != _header.end(); it++)
217 | {
218 | if (key == *it)
219 | {
220 | _values[pos] = value;
221 | return true;
222 | }
223 | pos++;
224 | }
225 | return false;
226 | }
227 |
228 | const std::string Row::operator[](unsigned int valuePosition) const
229 | {
230 | if (valuePosition < _values.size())
231 | return _values[valuePosition];
232 | throw Error("can't return this value (doesn't exist)");
233 | }
234 |
235 | const std::string Row::operator[](const std::string &key) const
236 | {
237 | std::vector::const_iterator it;
238 | int pos = 0;
239 |
240 | for (it = _header.begin(); it != _header.end(); it++)
241 | {
242 | if (key == *it)
243 | return _values[pos];
244 | pos++;
245 | }
246 |
247 | throw Error("can't return this value (doesn't exist)");
248 | }
249 |
250 | std::ostream &operator<<(std::ostream &os, const Row &row)
251 | {
252 | for (unsigned int i = 0; i != row._values.size(); i++)
253 | os << row._values[i] << " | ";
254 |
255 | return os;
256 | }
257 |
258 | std::ofstream &operator<<(std::ofstream &os, const Row &row)
259 | {
260 | for (unsigned int i = 0; i != row._values.size(); i++)
261 | {
262 | os << row._values[i];
263 | if (i < row._values.size() - 1)
264 | os << ",";
265 | }
266 | return os;
267 | }
268 | }
269 |
--------------------------------------------------------------------------------