Skip to content

Instantly share code, notes, and snippets.

@koturn
Created December 23, 2015 18:33
Show Gist options
  • Select an option

  • Save koturn/04714109987b0d204326 to your computer and use it in GitHub Desktop.

Select an option

Save koturn/04714109987b0d204326 to your computer and use it in GitHub Desktop.
Simple csv parser
#ifndef CSV_PARSER_H
#define CSV_PARSER_H
/*!
* @brief Simple csv parser
* @author koturn
* @date 2015 12/24
* @file CsvParser.h
* @version 0.1
*/
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <iostream>
template<typename DlmType>
static inline std::vector<std::string>
split(std::string line, const DlmType &delimiter);
/*!
* @brief Simple csv parser
*/
class CsvParser {
private:
std::ifstream fileStream;
public:
CsvParser(void) :
fileStream()
{}
CsvParser(const std::string &csvFilename) :
fileStream(csvFilename.c_str())
{}
CsvParser(const char *csvFilename) :
fileStream(csvFilename)
{}
bool setFile(const std::string &csvFilename)
{
return setFile(csvFilename.c_str());
}
bool setFile(const char *csvFilename)
{
fileStream.open(csvFilename);
return !fileStream.fail();
}
template<typename ElmType, typename DlmType>
std::vector<std::vector<ElmType> > parseAll(const DlmType &delimiter);
template<typename ElmType, typename DlmType>
void _parseAll(std::vector<std::vector<ElmType> > &csvElms, const DlmType &delimiter);
template<typename DlmType>
std::vector<std::vector<std::string> > parseAll(const DlmType &delimiter);
template<typename DlmType>
void _parseAll(std::vector<std::vector<std::string> > &csvElms, const DlmType &delimiter);
template<typename ElmType, typename DlmType, typename FuncType>
std::vector<std::vector<ElmType> > parse(const DlmType &delimiter, const FuncType &operation);
template<typename ContType, typename DlmType, typename FuncType>
void _parse(ContType &container, const DlmType &delimiter, const FuncType &operation);
}; // class CsvParser
/*!
* @brief Parse csv file
*
* @code
* CsvParser cr("sample.csv");
* std::vector<std::vector<int> > vct = cr.parseAll<int>(',');
* @endcode
*
* @tparam ElmType Type of csv-element
* @tparam DlmType Type of delimiter (Assumption: std::string, const char *, char)
* @param [in] delimiter Delimiter of csv file
*
* @return 2D vector of csv-elements (All element type is ElmType)
*/
template<typename ElmType, typename DlmType>
std::vector<std::vector<ElmType> >
CsvParser::parseAll(const DlmType &delimiter)
{
std::vector<std::vector<ElmType> > csvElms;
_parseAll(csvElms, delimiter);
return csvElms;
}
/*!
* @brief Parse csv file (specialized for std::string)
*
* @code
* CsvParser cr("sample.csv");
* std::vector<std::vector<std::string> > vct = cr.parseAll(',');
* @endcode
*
* @tparam DlmType Type of delimiter (Assumption: std::string, const char *, char)
* @param [in] delimiter Delimiter of csv file
*
* @return 2D vector of csv-elements (All element type is std::string)
*/
template<typename DlmType>
std::vector<std::vector<std::string> >
CsvParser::parseAll(const DlmType &delimiter)
{
std::vector<std::vector<std::string> > csvElms;
_parseAll(csvElms, delimiter);
return csvElms;
}
/*!
* @brief Parse csv file
*
* @tparam ElmType Type of csv-element
* @tparam DlmType Type of delimiter (Assumption: std::string, const char *, char)
* @param [out] csvElms 2D vector to store csv-elements (All element type is ElmType)
* @param [in] delimiter Delimiter of csv file
*/
template<typename ElmType, typename DlmType>
void
CsvParser::_parseAll(
std::vector<std::vector<ElmType> > &csvElms,
const DlmType &delimiter)
{
if (!fileStream) {
throw "Bad stream";
}
std::string line;
std::stringstream ss;
while (fileStream >> line) {
std::vector<std::string> _lineElms = split(line, delimiter);
std::vector<ElmType> lineElms(_lineElms.size());
int idx = 0;
for (std::vector<std::string>::const_iterator itr = _lineElms.begin(); itr != _lineElms.end(); ++itr) {
ss << *itr;
ss >> lineElms[idx++];
ss.str("");
ss.clear(std::stringstream::goodbit);
}
csvElms.push_back(lineElms);
}
}
/*!
* @brief Parse csv file
*
* @tparam DlmType Type of delimiter (Assumption: std::string, const char *, char)
* @param [out] csvElms 2D vector to store csv-elements (All element type is std::string)
* @param [in] delimiter Delimiter of csv file
*/
template<typename DlmType>
void
CsvParser::_parseAll(
std::vector<std::vector<std::string> > &csvElms,
const DlmType &delimiter)
{
if (!fileStream) {
throw "Bad stream";
}
std::string line;
while (fileStream >> line) {
std::vector<std::string> lineElms = split(line, delimiter);
csvElms.push_back(lineElms);
}
}
/*!
* @brief Parse csv file
*
* You can custamize reading action as second argument 'operation'
*
* @tparam ElmType Type of csv-element
* @tparam DlmType Type of delimiter (Assumption: std::string, const char *, char)
* @tparam FuncType Type of functional object (dummy)
* @param [in] delimiter Delimiter of csv file
* @param [in] operation Operation for one line in csv-file (Functional object)
*
* @return 2D vector of csv-elements (All element type is ElmType)
*/
template<typename ElmType, typename DlmType, typename FuncType>
std::vector<std::vector<ElmType> >
CsvParser::parse(
const DlmType &delimiter,
const FuncType &operation)
{
std::vector<std::vector<ElmType> > csvDatas;
_parse(csvDatas, delimiter, operation);
return csvDatas;
}
/*!
* @brief Parse csv file
*
* You can custamize reading action as second argument 'operation'
*
* @code
* #include <cstdlib>
* #include <sstream>
* #include <vector>
* #include "CsvParser.h"
*
* struct CustomOperation
* {
* void operator()(std::vector<std::vector<double> > &container, const std::vector<std::string> &lineElms) const
* {
* std::stringstream ss;
* std::vector<double> customLineElms;
* for (std::vector<std::string>::const_iterator itr = lineElms.begin(); itr != lineElms.end(); ++itr) {
* double e;
* ss << *itr;
* ss >> e;
* ss.str("");
* ss.clear(std::stringstream::goodbit);
* customLineElms.push_back(e);
* }
* container.push_back(customLineElms);
* }
* };
*
* int
* main(void)
* {
* CsvParser cr("sample.csv");
* std::vector<std::vector<double> > vct = cr.parse<double>(',', CustomOperation());
* // ...
* return EXIT_SUCCESS;
* }
* @endcode
*
* @tparam ContType Type of element-container (for example, std::vector<std::vector<int> >)
* @tparam DlmType Type of delimiter (Assumption: std::string, const char *, char)
* @tparam FuncType Type of functional object (dummy)
* @param [out] container element-container
* @param [in] delimiter Delimiter of csv file
* @param [in] operation Operation for one line in csv-file (Functional object)
*/
template<typename ContType, typename DlmType, typename FuncType>
void
CsvParser::_parse(
ContType &container,
const DlmType &delimiter,
const FuncType &operation)
{
if (!fileStream) {
throw "Bad stream";
}
std::string line;
while (fileStream >> line) {
std::vector<std::string> lineElms = split(line, delimiter);
operation(container, lineElms);
}
}
/*!
* @brief Split string by specified delimiter
* @param [in] line One line
* @param [in] delimiter Separate charactor or string
* @return line-elements (as std::vector)
*/
template<typename DlmType>
static inline std::vector<std::string>
split(std::string line, const DlmType &delimiter)
{
std::vector<std::string> lineElms;
int pos;
while ((pos = line.find_first_of(delimiter)) != std::string::npos) {
if (pos > 0) {
lineElms.push_back(line.substr(0, pos));
}
line = line.substr(pos + 1);
}
if (line.length() > 0) {
lineElms.push_back(line);
}
return lineElms;
}
#endif // CSV_PARSER_H
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment