As a background for parsing (optionally) delimited and delimited fields, including different quotation marks ( ' , " ), see here:
- Parse lines with boost :: spirit
For a very, very, very complete example, complete with support for partially quoted values ββand a
splitInto(input, output, ' ');
which accepts "arbitrary" output containers and delimiter expressions, see here:
- How to make my split work only on one real line and be able to skip the quoted parts of the line?
Turning to your exact question, assuming either cited or disordered fields (without partial quotes inside the field values) using Spirit V2:
Take the simplest "abstract data type" that could work:
using Column = std::string; using Columns = std::vector<Column>; using CsvLine = Columns; using CsvFile = std::vector<CsvLine>;
And a repeated double quote avoids the semantics of double quotes (as I pointed out in the comment), you should use something like:
static const char colsep = ','; start = -line % eol; line = column % colsep; column = quoted | *~char_(colsep); quoted = '"' >> *("\"\"" | ~char_('"')) >> '"';
The following full test program prints
[1997][Ford][E350][ac, abs, moon][rusty][3001.00]
(Note that BOOST_SPIRIT_DEBUG defines for easy debugging). Watch Live on Coliru
Full demo
//#define BOOST_SPIRIT_DEBUG #include <boost/spirit/include/qi.hpp> namespace qi = boost::spirit::qi; using Column = std::string; using Columns = std::vector<Column>; using CsvLine = Columns; using CsvFile = std::vector<CsvLine>; template <typename It> struct CsvGrammar : qi::grammar<It, CsvFile(), qi::blank_type> { CsvGrammar() : CsvGrammar::base_type(start) { using namespace qi; static const char colsep = ','; start = -line % eol; line = column % colsep; column = quoted | *~char_(colsep); quoted = '"' >> *("\"\"" | ~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 = R"(1997,Ford,E350,"ac, abs, moon","""rusty""",3001.00)"; auto f(begin(s)), l(end(s)); CsvGrammar<std::string::const_iterator> p; CsvFile parsed; bool ok = qi::phrase_parse(f,l,p,qi::blank,parsed); if (ok) { for(auto& line : parsed) { for(auto& col : line) std::cout << '[' << col << ']'; std::cout << std::endl; } } else { std::cout << "Parse failed\n"; } if (f!=l) std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n"; }