我正在尝试解析以下内容:
[SOFT] AQUA+
[FORWARD_SPEED] 0.00
[some other key] string value
[PERIODS_NUMBER] 6
[HEADINGS_NUMBER] 13
[LOWEST_HEADINGS] 0.00
[HIGHEST_HEADINGS] 180.00
我事先并不知道钥匙是什么。
我想在向量结构中解析它们。
namespace hdb
{
typedef std::string Header;
template <typename T> struct Key
{
Header header;
T value;
};
struct AST
{
std::vector<Key<std::string> > string_keys;
std::vector<Key<double> > value_keys;
}
}
我写了适配器:
BOOST_FUSION_ADAPT_STRUCT(
hdb::Key<std::string>,
(hdb::Header, header)
(std::string, value)
)
BOOST_FUSION_ADAPT_STRUCT(
hdb::Key<double>,
(hdb::Header, header)
(double, value)
)
namespace boost { namespace spirit { namespace traits {
template<>
struct is_container<hdb::AST, void> : mpl::true_ { };
template<>
struct container_value<hdb::AST, void> {
typedef boost::variant<
hdb::Key<std::string>
,hdb::Key<double>
> type;
};
template <>
struct push_back_container<hdb::AST, hdb::Key<std::string>, void> {
static bool call(hdb::AST& f, const hdb::Key<std::string>& val) {
f.string_keys.push_back(val);
return true;
}
};
template <>
struct push_back_container<hdb::AST, hdb::Key<double>, void> {
static bool call(hdb::AST& f, const hdb::Key<double>& val) {
f.value_keys.push_back(val);
return true;
}
};
语法如下:
template <typename Iterator>
struct hdb_grammar : qi::grammar<Iterator, hdb::AST(), ascii::space_type>
{
hdb_grammar() : hdb_grammar::base_type(ast)
{
ast %= string_key | value_key;
header %= lexeme['[' >> +(char_ - '[' - ']') >> ']'];
string_key %= header >> +(char_ - '[' - ']');
value_key %= header >> double_;
}
qi::rule<Iterator, hdb::AST(), ascii::space_type> ast;
qi::rule<Iterator, hdb::Header(), ascii::space_type> header;
qi::rule<Iterator, hdb::Key<double>(), ascii::space_type> value_key;
qi::rule<Iterator, hdb::Key<std::string>(), ascii::space_type> string_key;
};
我像这样调用解析器:
const std::string contents = "[key 1] value 1\n"
"[key 2] value 2\n";
typedef hdb_grammar<std::string::const_iterator> grammar;
grammar g; // Our grammar
hdb::AST ast; // Our tree
using boost::spirit::ascii::space;
std::string::const_iterator begin = contents.begin(), end = contents.end();
bool success = qi::phrase_parse(begin, end, g.ast, space, ast); // Only fills "key 1" & not "key 2"
我认为问题在于我的语法,但我不能为我的生活看到它的错误。任何帮助将不胜感激。
答案 0 :(得分:1)
您只需有效地解析(string_key | value_key)
。如果您想重复此操作,请使用Kleene star或plus:
bool success = qi::phrase_parse(begin, end, *g, space, ast);
这允许0个或更多AST匹配,每次都会传递相同的属性。
使用调试信息查看 Live On Coliru 。
那就是说,我宁愿用自然的灵魂模式来写同样的东西。这是22行(从~100)包含的相同功能:
#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/spirit/include/qi.hpp>
#include <map>
typedef boost::variant<double, std::string> Value;
typedef std::map<std::string, Value> AST;
int main() {
namespace qi = boost::spirit::qi;
typedef boost::spirit::istream_iterator It;
static qi::rule<It, std::string()> const string_ = +~qi::char_("[]\r\n");
It begin(std::cin >> std::noskipws), end;
AST ast;
bool success = qi::phrase_parse(begin, end,
('[' >> string_ >> ']' >> (qi::double_|string_)) % qi::eol,
qi::blank, ast);
if (success) for (auto& e : ast)
std::cout << '[' << e.first << "]\t" << e.second << "\n";
}
打印
[FORWARD_SPEED] 0
[HEADINGS_NUMBER] 13
[HIGHEST_HEADINGS] 180
[LOWEST_HEADINGS] 0
[PERIODS_NUMBER] 6
[SOFT] AQUA+
[some other key] string value