//#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
typedef std::string Column;
typedef std::vector<Column> Columns;
typedef Columns CsvLine;
typedef std::vector<CsvLine> CsvFile;
template <typename It>
struct CsvGrammar : qi::grammar<It, CsvFile(), qi::blank_type>
{
CsvGrammar() : CsvGrammar::base_type(start)
{
static const char colsep = ',';
start = -line % qi::eol;
line = column % colsep;
column = quoted | *~qi::char_(colsep);
quoted = '"' >> *("\"\"" | ~qi::char_('"')) >> '"';
BOOST_SPIRIT_DEBUG_NODES((start)(line)(column)(quoted));
}
private:
qi::rule<It, CsvFile(), qi::blank_type> start;
qi::rule<It, CsvLine(), qi::blank_type> line;
qi::rule<It, Column(), qi::blank_type> column;
qi::rule<It, std::string()> quoted;
};
int main()
{
const std::string s = "1997,Ford,E350,\"ac, abs, moon\",\"\"\"rusty\"\"\",3001.00";
typedef std::string::const_iterator It;
It f(s.begin()), l(s.end());
CsvGrammar<It> p;
CsvFile parsed;
bool ok = qi::phrase_parse(f,l,p,qi::blank,parsed);
if (ok)
{
for (CsvFile::const_iterator lit = parsed.begin(); lit != parsed.end(); ++lit) {
for (Columns::const_iterator cit = lit->begin(); cit != lit->end(); ++cit)
std::cout << '[' << *cit << ']';
std::cout << std::endl;
}
} else
{
std::cout << "Parse failed\n";
}
if (f!=l)
std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}
Ly8jZGVmaW5lIEJPT1NUX1NQSVJJVF9ERUJVRwojaW5jbHVkZSA8Ym9vc3Qvc3Bpcml0L2luY2x1ZGUvcWkuaHBwPgoKbmFtZXNwYWNlIHFpID0gYm9vc3Q6OnNwaXJpdDo6cWk7Cgp0eXBlZGVmIHN0ZDo6c3RyaW5nIENvbHVtbjsKdHlwZWRlZiBzdGQ6OnZlY3RvcjxDb2x1bW4+IENvbHVtbnM7CnR5cGVkZWYgQ29sdW1ucyBDc3ZMaW5lOwp0eXBlZGVmIHN0ZDo6dmVjdG9yPENzdkxpbmU+IENzdkZpbGU7Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgSXQ+CnN0cnVjdCBDc3ZHcmFtbWFyIDogcWk6OmdyYW1tYXI8SXQsIENzdkZpbGUoKSwgcWk6OmJsYW5rX3R5cGU+CnsKICAgIENzdkdyYW1tYXIoKSA6IENzdkdyYW1tYXI6OmJhc2VfdHlwZShzdGFydCkKICAgIHsKICAgICAgICBzdGF0aWMgY29uc3QgY2hhciBjb2xzZXAgPSAnLCc7CgogICAgICAgIHN0YXJ0ICA9IC1saW5lICUgcWk6OmVvbDsKICAgICAgICBsaW5lICAgPSBjb2x1bW4gJSBjb2xzZXA7CiAgICAgICAgY29sdW1uID0gcXVvdGVkIHwgKn5xaTo6Y2hhcl8oY29sc2VwKTsKICAgICAgICBxdW90ZWQgPSAnIicgPj4gKigiXCJcIiIgfCB+cWk6OmNoYXJfKCciJykpID4+ICciJzsKCiAgICAgICAgQk9PU1RfU1BJUklUX0RFQlVHX05PREVTKChzdGFydCkobGluZSkoY29sdW1uKShxdW90ZWQpKTsKICAgIH0KICBwcml2YXRlOgogICAgcWk6OnJ1bGU8SXQsIENzdkZpbGUoKSwgcWk6OmJsYW5rX3R5cGU+IHN0YXJ0OwogICAgcWk6OnJ1bGU8SXQsIENzdkxpbmUoKSwgcWk6OmJsYW5rX3R5cGU+IGxpbmU7CiAgICBxaTo6cnVsZTxJdCwgQ29sdW1uKCksICBxaTo6YmxhbmtfdHlwZT4gY29sdW1uOwogICAgcWk6OnJ1bGU8SXQsIHN0ZDo6c3RyaW5nKCk+IHF1b3RlZDsKfTsKCmludCBtYWluKCkKewogICAgY29uc3Qgc3RkOjpzdHJpbmcgcyA9ICIxOTk3LEZvcmQsRTM1MCxcImFjLCBhYnMsIG1vb25cIixcIlwiXCJydXN0eVwiXCJcIiwzMDAxLjAwIjsKCiAgICB0eXBlZGVmIHN0ZDo6c3RyaW5nOjpjb25zdF9pdGVyYXRvciBJdDsKICAgIEl0IGYocy5iZWdpbigpKSwgbChzLmVuZCgpKTsKICAgIENzdkdyYW1tYXI8SXQ+IHA7CgogICAgQ3N2RmlsZSBwYXJzZWQ7CiAgICBib29sIG9rID0gcWk6OnBocmFzZV9wYXJzZShmLGwscCxxaTo6YmxhbmsscGFyc2VkKTsKCiAgICBpZiAob2spCiAgICB7CiAgICAgICAgZm9yIChDc3ZGaWxlOjpjb25zdF9pdGVyYXRvciBsaXQgPSBwYXJzZWQuYmVnaW4oKTsgbGl0ICE9IHBhcnNlZC5lbmQoKTsgKytsaXQpIHsKICAgICAgICAgICAgZm9yIChDb2x1bW5zOjpjb25zdF9pdGVyYXRvciBjaXQgPSBsaXQtPmJlZ2luKCk7IGNpdCAhPSBsaXQtPmVuZCgpOyArK2NpdCkKICAgICAgICAgICAgICAgIHN0ZDo6Y291dCA8PCAnWycgPDwgKmNpdCA8PCAnXSc7CiAgICAgICAgICAgIHN0ZDo6Y291dCA8PCBzdGQ6OmVuZGw7CiAgICAgICAgfQogICAgfSBlbHNlCiAgICB7CiAgICAgICAgc3RkOjpjb3V0IDw8ICJQYXJzZSBmYWlsZWRcbiI7CiAgICB9CgogICAgaWYgKGYhPWwpCiAgICAgICAgc3RkOjpjb3V0IDw8ICJSZW1haW5pbmcgdW5wYXJzZWQ6ICciIDw8IHN0ZDo6c3RyaW5nKGYsbCkgPDwgIidcbiI7Cn0K