我是一個精神初學者使用boost精神(qi)解析英制值
我想使用spirit將一個英制字符串值解析爲一個結構體。
輸入應該接受以下語法:
5'3"1/2 5'1/2 3"1/2
的struct imp_constant
看起來是這樣,請注意以下流運算符,因爲這符不,我會打印結果:
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;
}
我的僞語法是非常簡單的,看起來像這樣:
myrule = (
(
(qi::uint_ >> L'\'')
||
(qi::uint_ >> L'"')
)
>> -(
qi::uint_
>> L'/' >>
qi::uint_
)
);
這裏是我的相當VE首先嚐試填充我的結構:
我添加BOOST_FUSION_ADAPT_STRUCT
宏來我struct imp_constant
然後試圖以下語法:
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]
)
];
結果是:
input:5'3"1/2 ==> output:5'3"1/2 (ok)
input:5'1/2 ==> output:5'1"1/2 (__nok__)
我想我不瞭解如何在這種情況下佔位符的行爲。
由於我在精神的世界初學者,任何意見,歡迎
非常感謝您
下面是完整的代碼,這應該有助於
#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;
}
非常感謝,它工作得很好!我會記住'| qi :: attr(...)'作爲可選的默認值技巧。 – loic 2013-04-10 13:42:16
+1也來自我:)我玩這個主意,但選擇保持接近原始並解釋發生了什麼。 (@loic屬性技巧實際上就是我簡單地用「_explicit defaults_或qi :: hold可以修復它」的方式暗示的) – sehe 2013-04-10 18:52:04
@sehe的確,user2266005找到的解決方案對我來說非常封閉!對於錯過「明確默認」提示的道歉,我幾天前發現了精神(順便說一句,我歡迎自己在這個新的世界:),儘管我已經閱讀了很多,但我還是不太滿意概念!感謝你們的幫助,你們在這裏和其他許多職位的貢獻讓精神對我更具吸引力。 – loic 2013-04-11 07:23:16