我有这个CSV行
std::string s = R"(1997,Ford,E350,"ac, abs, moon","some "rusty" parts",3000.00)";
我可以用解析它boost::tokenizer
:
typedef boost::tokenizer< boost::escaped_list_separator<char> , std::string::const_iterator, std::string> Tokenizer;
boost::escaped_list_separator<char> seps('\\', ',', '\"');
Tokenizer tok(s, seps);
for (auto i : tok)
{
std::cout << i << std::endl;
}
它得到它的权利,除了被剥夺得到令牌“生锈”应该有双引号。
这是我尝试使用boost ::精神
boost::spirit::classic::rule<> list_csv_item = !(boost::spirit::classic::confix_p('\"', *boost::spirit::classic::c_escape_ch_p, '\"') | boost::spirit::classic::longest_d[boost::spirit::classic::real_p | boost::spirit::classic::int_p]);
std::vector<std::string> vec_item;
std::vector<std::string> vec_list;
boost::spirit::classic::rule<> list_csv = boost::spirit::classic::list_p(list_csv_item[boost::spirit::classic::push_back_a(vec_item)],',')[boost::spirit::classic::push_back_a(vec_list)];
boost::spirit::classic::parse_info<> result = parse(s.c_str(), list_csv);
if (result.hit)
{
for (auto i : vec_item)
{
cout << i << endl;
}
}
问题:
不工作,打印第一令牌只
为什么提振::精神::经典? 找不到使用精神V2例子
设置是残酷的..但我可以用这个活
**我真的想用boost::spirit
,因为它往往是相当快
预期输出:
1997
Ford
E350
ac, abs, moon
some "rusty" parts
3000.00
Sehe的帖子好像比我更清洁公平一点,但我把这个共同的一点,所以这里是反正:
#include <boost/tokenizer.hpp>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
int main() {
const std::string s = R"(1997,Ford,E350,"ac, abs, moon",""rusty"",3000.00)";
// Tokenizer
typedef boost::tokenizer< boost::escaped_list_separator<char> , std::string::const_iterator, std::string> Tokenizer;
boost::escaped_list_separator<char> seps('\\', ',', '\"');
Tokenizer tok(s, seps);
for (auto i : tok)
std::cout << i << "\n";
std::cout << "\n";
// Boost Spirit Qi
qi::rule<std::string::const_iterator, std::string()> quoted_string = '"' >> *(qi::char_ - '"') >> '"';
qi::rule<std::string::const_iterator, std::string()> valid_characters = qi::char_ - '"' - ',';
qi::rule<std::string::const_iterator, std::string()> item = *(quoted_string | valid_characters );
qi::rule<std::string::const_iterator, std::vector<std::string>()> csv_parser = item % ',';
std::string::const_iterator s_begin = s.begin();
std::string::const_iterator s_end = s.end();
std::vector<std::string> result;
bool r = boost::spirit::qi::parse(s_begin, s_end, csv_parser, result);
assert(r == true);
assert(s_begin == s_end);
for (auto i : result)
std::cout << i << std::endl;
std::cout << "\n";
}
而这种输出:
1997
Ford
E350
ac, abs, moon
rusty
3000.00
1997
Ford
E350
ac, abs, moon
rusty
3000.00
一些值得注意的是 :这不会实现一个完整的CSV解析器。 你想也想看看还有什么需要为您实现转义字符或。
另外 :如果你正在寻找进入的文件,只要你知道,在齐, 'a'
等价于boost::spirit::qi::lit('a')
和"abc"
相当于boost::spirit::qi::lit("abc")
在双引号:那么,作为Sehe的评论指出上面,它不是直接清楚周围的规则是什么""
在输入文本手段。 如果你想要的所有实例""
不带引号的字符串内被转换为"
,然后像下面这样是可行的。
qi::rule<std::string::const_iterator, std::string()> double_quote_char = "\"\"" >> qi::attr('"');
qi::rule<std::string::const_iterator, std::string()> item = *(double_quote_char | quoted_string | valid_characters );
有关解析(可选)引述分隔的领域,包括不同的引号字符(背景'
, "
),在这里看到:
对于一个非常,非常,非常完整的例子完成与支持部分引用的值和
splitInto(input, output, ' ');
方法采用“任意”输出容器和分隔符表达式,在这里看到:
- 如何使我的工作拆分只在一个真实的线,并且能够跳过绳的引用部分?
解决您的具体问题,假设无论是 或不使用引号字段(域值内没有局部引号),使用精神V2:
让我们以最简单的“抽象数据类型”能够工作:
using Column = std::string;
using Columns = std::vector<Column>;
using CsvLine = Columns;
using CsvFile = std::vector<CsvLine>;
和重复双引号转义双引号语义(正如我在评论中指出),你应该能够使用这样的:
static const char colsep = ',';
start = -line % eol;
line = column % colsep;
column = quoted | *~char_(colsep);
quoted = '"' >> *("\"\"" | ~char_('"')) >> '"';
下面的完整的测试程序打印
[1997][Ford][E350][ac, abs, moon][rusty][3001.00]
(注意BOOST_SPIRIT_DEBUG定义,便于调试)。 看到它住在Coliru
完整的示例
//#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";
}