使用增强精神解释帝国价值 [英] Parsing imperial values using boost spirit (qi)
问题描述
我是一个精灵初学者
我想使用精神将英文字符串值解析成结构。
输入应该接受以下语法:
5'31/2
5'1 / 2
31/2
struct imp_constant
,请注意下面的stream运算符,我将按照此运算符打印结果:
struct imp_constant
{
explicit imp_constant(unsigned int feet = 0
,unsigned int inch = 0
,unsigned int fracn = 0
,unsigned int fracd = 1)
:feet_ ,inches_(inch),fracn_(fracn),fracd_(fracd){}
unsigned int feet_,inches_,fracn_,fracd_;
};
std :: ostream&运算符<<<(std :: ostream& os,imp_constant const& cst)
{
if(cst.feet_)
os< cst.feet_< '\'';
if(cst.inches_)
os<< cst.inches_< ''';
if(cst.fracn_)
os<< cst.fracn_<'/'<< cst.fracd_;
return os;
}
我的伪语法很简单,看起来像这样:
myrule =(
(
(qi :: uint_>> L'\'')
| |
(qi :: uint_>> L'')
)
>> - (
qi :: uint_
> L'/'>>
qi :: uint_
)
);
这是我非常天真的第一次尝试填充我的结构:
我已将 BOOST_FUSION_ADAPT_STRUCT
宏添加到我的 struct imp_constant
,然后尝试了以下语法:
qi :: rule< std :: string :: const_iterator,imp_constant()>
impconst = qi :: lexeme [//不确定这是必需的,因为没有队长精确化
(
(qi :: uint_ [phx :: at_c <0>(qi :: _ val) = qi :: _1]> L'''')
||
(qi :: uint_ [phx :: at_c 1(qi :: _ val)= qi :: _1]> L'')
)
> - (
qi :: uint_ [phx :: at_c 2 :: _ 1]
>> L'/'>>
qi :: uint_ [phx :: at_c 3(qi :: _ val)= qi :: _ 1]
)
];
结果是:
输入:5'31/2 ==>输出:5'31/2(ok)
输入:5'1 / 2 ==>输出:5'11/2(__nok__)
我想我不知道
_1
占位符在这种情况下的行为。
由于我是精神世界的初学者,欢迎任何建议。
非常感谢。
这是完整的代码,这将有助于
#define BOOST_SPIRIT_DONT_USE_MPL_ASSERT_MSG 1
/ /#define BOOST_SPIRIT_DEBUG<<取消注释以启用调试
#include< boost / spirit / include / qi.hpp>
#include< boost / spirit / include / phoenix.hpp>
#include< boost / variant / recursive_wrapper.hpp>
#include< boost / fusion / adapted.hpp>
命名空间qi = boost :: spirit :: qi;
namespace phx = boost :: phoenix;
struct imp_constant
{
explicit imp_constant(unsigned int feet = 0
,unsigned int inch = 0
,unsigned int fracn = 0
,unsigned int fracd = 1)
:feet_(feet),inches_(inch),fracn_(fracn),fracd_(fracd){}
unsigned int feet_,inches_,fracn_,fracd_;
};
std :: ostream&运算符<<<(std :: ostream& os,imp_constant const& cst)
{
if(cst.feet_)
os< cst.feet_< '\'';
if(cst.inches_)
os<< cst.inches_< ''';
if(cst.fracn_)
os<< cst.fracn_<'/'<< cst.fracd_;
return os;
}
BOOST_FUSION_ADAPT_STRUCT(imp_constant,
(unsigned int,feet_)
(unsigned int,inches_)
(unsigned int,fracn_)
unsigned int,fracd_))
int _tmain(int argc,_TCHAR * argv [])
{
std :: string input;
std :: cout<<\\\
---------------------- \\\
> ;
while(std :: getline(std :: cin,input))
{
if(input.empty()|| input [0] =='q'||输入[0] =='Q')
break;
std :: string :: const_iterator f(input.begin()),l(input.end());
try
{
imp_constant result;
std :: cout<<parsing:<<<<<\\\
;
bool ok;
qi :: rule< std :: string :: const_iterator,imp_constant()>
impconst = qi :: lexeme [// not sure this是必需的,因为
//没有预置的节点
(
(qi :: uint_ [phx :: at_c <0>(qi :: _ val)= qi :: _ 1]
>>>>>> L'\'')
||
(qi :: uint_ [phx :: at_c'(qi :: _ val)= qi :: _1]
>>> L'')
)
>> - (
qi :: uint_ [phx :: at_c 2(qi :: _ val)= qi :: _ 1]
>>>>>>
qi :: uint_ [phx :: at_c 3(qi :: _ val)= qi :: _ 1]
)
];
ok = qi :: phrase_parse(f,l,impconst,qi :: space,result)
if(!ok)
std :: cerr<< invalid input\\\
;
else
{
std :: cout< \\\
--------------------------- \\\
;
std :: cout<< result =<结果;
}
}
catch(const qi :: expectation_failure< const char *>& e)
{
std :: cerr< expect failure at'
<< std :: string(e.first,e.last)<< '\\\
;
}
catch(...)
{
std :: cerr< parse error\\\
;
}
if(f!= l)std :: cerr<< unparsed:'< std :: string(f,l)<< '\\\
;
std :: cout<< \ n ----------------------- \\\
>;
}
std :: getchar();
return 0;
}
解决方案您应该接受):
如果您将规则更改为:
qi :: rule< std :: string :: const_iterator,imp_constant()>
impconst =
(
(qi :: uint_>> L'\'')[phx :: at_c< 0>(qi :: _ val)= qi :: _ 1 ]
||
(qi :: uint_> L'')[phx :: at_c'(qi :: _ val)= qi :: _1]
)
>>
- (qi :: uint_>> L'/'>> qi :: uint_)
[phx :: at_c 2 :_val)= qi :: _1,phx :: at_c 3(qi :: _val)= qi :: _ 2]
;
我将如何做:
稍微改变你的
imp_constant
:结构分数
{
unsigned int n_,d_;
};
struct imp_constant
{
unsigned int feet_,inches_;
fraction frac_;
};
BOOST_FUSION_ADAPT_STRUCT(fraction,
(unsigned int,n_)
(unsigned int,d_)
)
BOOST_FUSION_ADAPT_STRUCT(imp_constant,
(unsigned int,feet_)
unsigned int,inches_)
(fraction,frac_)
然后规则是:
qi :: rule< std :: string :: const_iterator,unsigned int()> foot =(qi :: uint_>> L'\'')| qi :: attr(0);
qi :: rule< std :: string :: const_iterator,unsigned int()> inches =(qi :: uint_> L'')| qi :: attr(0);
qi :: rule< std :: string :: const_iterator,fraction qi :: uint_>>>>> L'/'>> qi :: uint_)|(qi :: attr(0)> qi :: attr(1));
qi :: rule< std :: string :: const_iterator,imp_constant()> impconst = feet>> inches>> fract;
b $ bI'm a spirit beginner
I'd like to parse an imperial string value into a struct using spirit.
The input should accept following syntaxes:
5'3"1/2 5'1/2 3"1/2the
struct imp_constant
looks like this, please note stream operator below, I'll print results as this operator does:struct imp_constant { explicit imp_constant(unsigned int feet=0 ,unsigned int inch=0 ,unsigned int fracn=0 ,unsigned int fracd=1) :feet_(feet),inches_(inch),fracn_(fracn),fracd_(fracd){} unsigned int feet_,inches_,fracn_,fracd_; }; std::ostream& operator<<(std::ostream& os, imp_constant const& cst) { if (cst.feet_) os << cst.feet_ << '\''; if (cst.inches_) os << cst.inches_ << '"'; if (cst.fracn_) os << cst.fracn_ << '/' << cst.fracd_; return os; }
my pseudo grammar is pretty simple and looks like this:
myrule = ( ( (qi::uint_ >> L'\'') || (qi::uint_ >> L'"') ) >> -( qi::uint_ >> L'/' >> qi::uint_ ) );
Here is my quite naive first try to populate my struct:
I've added
BOOST_FUSION_ADAPT_STRUCT
macro to mystruct imp_constant
then tried following grammar:qi::rule<std::string::const_iterator, imp_constant()> impconst = qi::lexeme[ //not sure this is required since no skipper precised ( (qi::uint_[phx::at_c<0>(qi::_val)=qi::_1] >> L'\'') || (qi::uint_[phx::at_c<1>(qi::_val)=qi::_1] >> L'"') ) >> -( qi::uint_[phx::at_c<2>(qi::_val)=qi::_1] >> L'/' >> qi::uint_[phx::at_c<3>(qi::_val)=qi::_1] ) ];
the result is:
input:5'3"1/2 ==> output:5'3"1/2 (ok) input:5'1/2 ==> output:5'1"1/2 (__nok__)
I guess I don't get how
_1
placeholder behaves in that case.Since I'm beginner in spirit's world, any advice is welcome
Thank you very much
Here is the full code, this should help
#define BOOST_SPIRIT_DONT_USE_MPL_ASSERT_MSG 1 //#define BOOST_SPIRIT_DEBUG << uncomment to enable debug #include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/phoenix.hpp> #include <boost/variant/recursive_wrapper.hpp> #include <boost/fusion/adapted.hpp> namespace qi = boost::spirit::qi; namespace phx = boost::phoenix; struct imp_constant { explicit imp_constant(unsigned int feet=0 ,unsigned int inch=0 ,unsigned int fracn=0 ,unsigned int fracd=1) :feet_(feet),inches_(inch),fracn_(fracn),fracd_(fracd){} unsigned int feet_,inches_,fracn_,fracd_; }; std::ostream& operator<<(std::ostream& os, imp_constant const& cst) { if (cst.feet_) os << cst.feet_ << '\''; if (cst.inches_) os << cst.inches_ << '"'; if (cst.fracn_) os << cst.fracn_ << '/' << cst.fracd_; return os; } BOOST_FUSION_ADAPT_STRUCT(imp_constant, (unsigned int, feet_) (unsigned int, inches_) (unsigned int, fracn_) (unsigned int, fracd_)) int _tmain(int argc, _TCHAR* argv[]) { std::string input; std::cout << "\n----------------------\n> "; while (std::getline(std::cin, input)) { if (input.empty() || input[0] == 'q' || input[0] == 'Q') break; std::string::const_iterator f(input.begin()),l(input.end()); try { imp_constant result; std::cout << "parsing: " << input << "\n"; bool ok; qi::rule<std::string::const_iterator, imp_constant()> impconst = qi::lexeme[ //not sure this is required since //no skipper precised ( (qi::uint_[phx::at_c<0>(qi::_val)=qi::_1] >> L'\'') || (qi::uint_[phx::at_c<1>(qi::_val)=qi::_1] >> L'"') ) >> -( qi::uint_[phx::at_c<2>(qi::_val)=qi::_1] >> L'/' >> qi::uint_[phx::at_c<3>(qi::_val)=qi::_1] ) ]; ok=qi::phrase_parse(f,l,impconst ,qi::space,result); if (!ok) std::cerr << "invalid input\n"; else { std::cout << "\n---------------------------\n"; std::cout << "result="<< result; } } catch (const qi::expectation_failure<const char *>& e) { std::cerr << "expect failure at '" << std::string(e.first, e.last) << "'\n"; } catch (...) { std::cerr << "parse error\n"; } if (f!=l) std::cerr << "unparsed: '" << std::string(f,l) << "'\n"; std::cout << "\n-----------------------\n> "; } std::getchar(); return 0; }
解决方案As alternatives to sehe's answer(that you should accept):
Your solution would work if you just changed your rule to:
qi::rule<std::string::const_iterator, imp_constant()> impconst = ( (qi::uint_ >> L'\'')[phx::at_c<0>(qi::_val)=qi::_1] || (qi::uint_ >> L'"')[phx::at_c<1>(qi::_val)=qi::_1] ) >> -(qi::uint_ >> L'/' >> qi::uint_) [phx::at_c<2>(qi::_val)=qi::_1,phx::at_c<3>(qi::_val)=qi::_2] ;
How I would do this:
Changing slightly your
imp_constant
:struct fraction { unsigned int n_,d_; }; struct imp_constant { unsigned int feet_,inches_; fraction frac_; }; BOOST_FUSION_ADAPT_STRUCT(fraction, (unsigned int, n_) (unsigned int, d_) ) BOOST_FUSION_ADAPT_STRUCT(imp_constant, (unsigned int, feet_) (unsigned int, inches_) (fraction , frac_)
And then the rule would be:
qi::rule<std::string::const_iterator,unsigned int()> feet = (qi::uint_ >> L'\'') | qi::attr(0); qi::rule<std::string::const_iterator,unsigned int()> inches = (qi::uint_ >> L'"') | qi::attr(0); qi::rule<std::string::const_iterator,fraction()> fract = (qi::uint_ >> L'/' >> qi::uint_) | (qi::attr(0)>> qi::attr(1)); qi::rule<std::string::const_iterator, imp_constant()> impconst=feet>>inches>>fract;
这篇关于使用增强精神解释帝国价值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!