kntty.hateblo.jp

ここに何か書く。

operator()でCSVパーサ

boost::program_optionsの
operator()の使い方に触発されて、
CSVパーサを実装。

#include <fstream>
#include <boost/tokenizer.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
typedef boost::char_separator<char> separator;
typedef boost::tokenizer<separator> tokenizer;

// CSVパーサクラス
class CsvParser
{
	std::ifstream m_ifs;
	const string m_file;
	tokenizer::const_iterator m_tok;
	tokenizer::const_iterator m_tokEnd;
public:
	CsvParser(const string& file) : m_file(file), m_ifs()
	{
		m_ifs.open(file);
	}
	~CsvParser(void)
	{
		m_ifs.close();
	}
        // 次の行へ
	bool next(void)
	{
		bool readStat;
		if (!m_ifs)
		{
			return false;
		}
		std::string line;
		try
		{
			readStat = (bool) getline(m_ifs, line);
			if (readStat)
			{
				tokenizer tokens(line, separator(","));
				m_tok = tokens.begin();
				m_tokEnd = tokens.end();
			}
		}
		catch (std::exception &ex)
		{
			readStat = false;
		}
		return readStat;
	}

        // ()の連結で、各要素を取得
	template<typename T>
	CsvParser& operator() (T* v)
	{
		if (m_tok == m_tokEnd)
		{
			throw std::exception("no more token in this line.");
		}
		try
		{
			*v = boost::lexical_cast<T>(boost::trim_copy(*m_tok));
			++m_tok;
		}
		catch (std::exception &ex)
		{
			std::cerr << ex.what() << std::endl;
			v = NULL;
		}
		return *this;
	}
};

//実行
int main(int argc, char** argv)
{
	CsvParser csv("input.csv");
	int id;
	string name;
	double val;
	while ( csv.next() )
	{
		csv(&id)(&name)(&val);
		cout << "ID:"<< id << ",Name:" << name << ",Value:" << val << endl;
	}

	return 0;
}

この実装なら、operator>>を使ったほうが素直かしら。