├── CMakeLists.txt ├── CSVparser.cpp ├── CSVparser.hpp ├── LICENSE ├── README.md └── files ├── readme.csv ├── simple.csv └── wiki.csv /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(csv) 2 | 3 | add_library(csv-parser 4 | CSVparser.cpp 5 | CSVparser.hpp 6 | ) -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | ``` -------------------------------------------------------------------------------- /files/readme.csv: -------------------------------------------------------------------------------- 1 | Year,Make,Model 2 | 1997,Ford,E350 3 | 2000,Mercury,Cougar -------------------------------------------------------------------------------- /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 --------------------------------------------------------------------------------