boost::spirit可选解析为融合自适应结构
boost::spirit optional parsing into a fusion adapted structure
如果存在结构
struct price
{
int chicken;
int cow;
bool in_stock;
std::string place;
};
其使用boost::fusion进行适配。如果需要解析它,但可以选择in_stock和place。例如
template <typename it, typename skipper = qi::space_type>
struct p : qi::grammar<it, price(), skipper>
{
p() : p::base_type(p_instance)
{
using namespace qi;
psr %= int_ > int_ > -bool_ > -('"' > char_ % ',' > '"');
}
private:
qi::rule<it,price(),skipper> limit;
};
然而,这是行不通的。如果输入是"2 3 "Chili""
,则会引发异常。什么是解决方案?
首先
我想您有太多的>
期望点,可能/应该是>>
序列运算符。
我想说,让你的语法更明确,例如说
bool_ | attr(false)
以确保如果bool_
失败,则会暴露false
的结果属性值。这样,暴露的属性是bool
,而不是boost::optional<bool>
,后者与目标结构(price
)更兼容。
演示:
template <typename It, typename Skipper = qi::space_type>
struct parser : qi::grammar<It, price(), Skipper>
{
parser() : parser::base_type(start)
{
using namespace qi;
in_stock = bool_ | attr(false);
start = int_ > int_ > in_stock > -('"' >> char_ % ',' > '"');
}
private:
qi::rule<It, price(), Skipper> start;
qi::rule<It, bool()> in_stock;
};
第二
然后,
('"' > char_ % ',' > '"')
只会匹配像"a"
、"b,c,d"
等字符串。如果你想让"Chili"
解析,你可能应该把它改成:
place = '"' >> *~char_('"') > '"';
start = int_ > int_ > in_stock > (place | attr(""));
这意味着解析由'"'
分隔的任何字符串(~char_("abc)
的意思是:除[abc]之外的任何字符)。
样品溶液
以下是完整的演示:
- 结构的融合自适应
- 上述调整后的语法
- 使用BOOstrongPIRIT_DEBUG进行调试
- 捕获
qi::expectation_failure
以打印解析失败的诊断 - 使用精神因果报应以人类可读的形式打印解析结果
测试程序输出如下:
代码
#define BOOST_SPIRIT_DEBUG
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
namespace qi = boost::spirit::qi;
namespace karma = boost::spirit::karma;
namespace phx = boost::phoenix;
struct price
{
int chicken;
int cow;
bool in_stock;
std::string place;
};
BOOST_FUSION_ADAPT_STRUCT(price,
(int, chicken)
(int, cow)
(bool, in_stock)
(std::string, place))
template <typename It, typename Skipper = qi::space_type>
struct parser : qi::grammar<It, price(), Skipper>
{
parser() : parser::base_type(start)
{
using namespace qi;
in_stock = bool_ | attr(false);
#if 0
start = int_ > int_ > in_stock > -('"' >> char_ % ',' > '"');
#else
place = '"' >> *~char_('"') > '"';
start = int_ > int_ > in_stock > (place | attr(""));
#endif
BOOST_SPIRIT_DEBUG_NODE(start);
BOOST_SPIRIT_DEBUG_NODE(place);
BOOST_SPIRIT_DEBUG_NODE(in_stock);
}
private:
qi::rule<It, price(), Skipper> start;
//
qi::rule<It, bool()> in_stock;
qi::rule<It, std::string()> place; // no skipper
};
bool doParse(const std::string& input)
{
typedef std::string::const_iterator It;
auto f(begin(input)), l(end(input));
parser<It, qi::space_type> p;
price data;
try
{
bool ok = qi::phrase_parse(f,l,p,qi::space,data);
if (ok)
{
std::cout << "parse success: '" << input << "'n";
std::cout << "data: " << karma::format_delimited(karma::eps <<
"chicken:" << karma::int_ <<
"cow:" << karma::int_ <<
"in_stock:" << karma::bool_ <<
"place:" << karma::auto_,
" ", data) << "n";
}
else std::cerr << "parse failed: '" << std::string(f,l) << "'n";
if (f!=l) std::cerr << "trailing unparsed: '" << std::string(f,l) << "'n";
return ok;
} catch(const qi::expectation_failure<It>& e)
{
std::string frag(e.first, e.last);
std::cerr << e.what() << "'" << frag << "'n";
}
return false;
}
int main()
{
doParse("1 2 true "a,b,c,d,e,f"");
doParse("3 4 "a,b,c,d,e,f"");
doParse("5 6");
doParse("7 8 false");
}
输出
<start>
<try>1 2 true "a,b,c,d,e,</try>
<in_stock>
<try>true "a,b,c,d,e,f"</try>
<success> "a,b,c,d,e,f"</success>
<attributes>[1]</attributes>
</in_stock>
<place>
<try>"a,b,c,d,e,f"</try>
<success></success>
<attributes>[[a, ,, b, ,, c, ,, d, ,, e, ,, f]]</attributes>
</place>
<success></success>
<attributes>[[1, 2, 1, [a, ,, b, ,, c, ,, d, ,, e, ,, f]]]</attributes>
</start>
parse success: '1 2 true "a,b,c,d,e,f"'
data: chicken: 1 cow: 2 in_stock: true place: a,b,c,d,e,f
<start>
<try>3 4 "a,b,c,d,e,f"</try>
<in_stock>
<try>"a,b,c,d,e,f"</try>
<success>"a,b,c,d,e,f"</success>
<attributes>[0]</attributes>
</in_stock>
<place>
<try>"a,b,c,d,e,f"</try>
<success></success>
<attributes>[[a, ,, b, ,, c, ,, d, ,, e, ,, f]]</attributes>
</place>
<success></success>
<attributes>[[3, 4, 0, [a, ,, b, ,, c, ,, d, ,, e, ,, f]]]</attributes>
</start>
parse success: '3 4 "a,b,c,d,e,f"'
data: chicken: 3 cow: 4 in_stock: false place: a,b,c,d,e,f
<start>
<try>5 6</try>
<in_stock>
<try></try>
<success></success>
<attributes>[0]</attributes>
</in_stock>
<place>
<try></try>
<fail/>
</place>
<success></success>
<attributes>[[5, 6, 0, []]]</attributes>
</start>
parse success: '5 6'
data: chicken: 5 cow: 6 in_stock: false place:
<start>
<try>7 8 false</try>
<in_stock>
<try>false</try>
<success></success>
<attributes>[0]</attributes>
</in_stock>
<place>
<try></try>
<fail/>
</place>
<success></success>
<attributes>[[7, 8, 0, []]]</attributes>
</start>
parse success: '7 8 false'
data: chicken: 7 cow: 8 in_stock: false place:
相关文章:
- 如何循环打印顶点结构
- 通过方法访问结构
- 使用不带参数的函数访问结构元素
- 预处理器:插入结构名称中的前一个行号
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 孤立代码块在结构中引发异常
- 有什么方法可以遍历结构吗
- 如何在 C# 中映射双 C 结构指针?
- 如何在C++中使用结构生成映射
- 无法将结构注册为增强几何体3D点
- 多成员Constexpr结构初始化
- 使用加速融合获取结构名称
- 如何检查助推融合序列是否为自适应结构
- 用枚举场和STL容器解析结构,并使用增强精神/融合轻松
- 在 Boost.Spirit 中,为什么向量(包裹在结构中)需要融合包装器,而不是变体?
- 调整定义/包含生成的结构以增强::融合
- 为加速融合调整空结构
- 结构和类的Boost融合序列类型和名称标识
- boost::spirit可选解析为融合自适应结构
- 使用元组和boost.融合,有理由使用结构吗