你只是想确保你解析“空”字符串的值。
value = +(char_ - ',' - eol) | attr("(unspecified)");
entry = value >> ',' >> value >> ',' >> value >> eol;
观看演示:
Live On Coliru
//#define BOOST_SPIRIT_DEBUG
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
struct data {
std::string a;
std::string b;
std::string c;
};
BOOST_FUSION_ADAPT_STRUCT(data, (std::string, a)(std::string, b)(std::string, c))
template <typename Iterator, typename skipper = qi::blank_type>
struct google_parser : qi::grammar<Iterator, data(), skipper> {
google_parser() : google_parser::base_type(entry, "contacts") {
using namespace qi;
value = +(char_ - ',' - eol) | attr("(unspecified)");
entry = value >> ',' >> value >> ',' >> value >> eol;
BOOST_SPIRIT_DEBUG_NODES((value)(entry))
}
private:
qi::rule<Iterator, std::string()> value;
qi::rule<Iterator, data(), skipper> entry;
};
int main() {
using It = std::string::const_iterator;
google_parser<It> p;
for (std::string input : {
"something, awful, is\n",
"fine,,just\n",
"like something missing: ,,\n",
})
{
It f = input.begin(), l = input.end();
data parsed;
bool ok = qi::phrase_parse(f,l,p,qi::blank,parsed);
if (ok)
std::cout << "Parsed: '" << parsed.a << "', '" << parsed.b << "', '" << parsed.c << "'\n";
else
std::cout << "Parse failed\n";
if (f!=l)
std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}
}
打印:
Parsed: 'something', 'awful', 'is'
Parsed: 'fine', '(unspecified)', 'just'
Parsed: 'like something missing: ', '(unspecified)', '(unspecified)'
但是,你有一个更大的问题。假设qi::repeat(2) [ value ]
将解析为2个字符串不起作用。
repeat
,像operator*
,operator+
和operator%
解析成容器属性。在这种情况下,容器属性(字符串)将接收输入从第二value
还有:
Live On Coliru
Parsed: 'somethingawful', 'is', ''
Parsed: 'fine(unspecified)', 'just', ''
Parsed: 'like something missing: (unspecified)', '(unspecified)', ''
由于这是不是你想要的,考虑你的数据类型:
的auto_
方法:
如果您教Qi如何提取单个值,您可以使用一个简单的规则,如
entry = skip(skipper() | ',') [auto_] >> eol;
这样一来,Spirit本身就会为给定的Fusion序列生成正确数量的值提取!
这里有一个快速的脏方法:
CAVEAT专业为std::string
直接像这可能不是最好的主意(它可能并不总是合适的,并可能与其他解析器严重交互)。然而,在默认情况下create_parser<std::string>
未定义(因为,它会做什么?),所以我抓住了机会,这个演示的目的:
namespace boost { namespace spirit { namespace traits {
template <> struct create_parser<std::string> {
typedef proto::result_of::deep_copy<
BOOST_TYPEOF(
qi::lexeme [+(qi::char_ - ',' - qi::eol)] | qi::attr("(unspecified)")
)
>::type type;
static type call() {
return proto::deep_copy(
qi::lexeme [+(qi::char_ - ',' - qi::eol)] | qi::attr("(unspecified)")
);
}
};
}}}
再次,看演示输出:
Live On Coliru
Parsed: 'something', 'awful', 'is'
Parsed: 'fine', 'just', '(unspecified)'
Parsed: 'like something missing: ', '(unspecified)', '(unspecified)'
备注有些先进的魔法让船长“恰到好处”工作(见skip()[]
和lexeme[]
)。一些一般性的解释可以在这里找到:Boost spirit skipper issues
UPDATE
容器方法
有一个微妙了这一点。其实两个。所以这里有一个演示:
Live On Coliru
//#define BOOST_SPIRIT_DEBUG
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
struct data {
std::vector<std::string> parts;
};
BOOST_FUSION_ADAPT_STRUCT(data, (std::vector<std::string>, parts))
template <typename Iterator, typename skipper = qi::blank_type>
struct google_parser : qi::grammar<Iterator, data(), skipper> {
google_parser() : google_parser::base_type(entry, "contacts") {
using namespace qi;
qi::as<std::vector<std::string> > strings;
value = +(char_ - ',' - eol) | attr("(unspecified)");
entry = strings [ repeat(2) [ value >> ',' ] >> value ] >> eol;
BOOST_SPIRIT_DEBUG_NODES((value)(entry))
}
private:
qi::rule<Iterator, std::string()> value;
qi::rule<Iterator, data(), skipper> entry;
};
int main() {
using It = std::string::const_iterator;
google_parser<It> p;
for (std::string input : {
"something, awful, is\n",
"fine,,just\n",
"like something missing: ,,\n",
})
{
It f = input.begin(), l = input.end();
data parsed;
bool ok = qi::phrase_parse(f,l,p,qi::blank,parsed);
if (ok) {
std::cout << "Parsed: ";
for (auto& part : parsed.parts)
std::cout << "'" << part << "' ";
std::cout << "\n";
}
else
std::cout << "Parse failed\n";
if (f!=l)
std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}
}
的精妙之处是:
我注意到 - 在编写答案之后 - 你认为输入是CSV。请参阅[如何使用Spirit解析CSV](http://stackoverflow.com/questions/18365463/h/18366335#18366335)和[this other answer](http://stackoverflow.com/questions/7436481/h/) 7462539#7462539)(以及[适用于映射文件的零拷贝分析](http://stackoverflow.com/questions/23699731/s/23703810#23703810))。还有一个映射列:[提高精神解析CSV与变量顺序列](http://stackoverflow.com/questions/27967195/b/27967473#27967473)。为了您的灵感 – sehe 2015-03-09 00:55:03
sehe,感谢您的深入解答。你不仅非常清楚,而且你不厌其烦地写出完整的例子。像你这样的人让stackoverflow值得。 – 2015-03-09 20:35:04