给出一个字符串“ 1、2、3、10、15”, 预期的输出应为01、02、03、10、15-即,如果大小不为2,则将“ 0”附加到已解析的属性中。我很容易使用lambda作为语义动作来做到这一点,但是如何完成任务而无需使用它们?我怀疑应该在这里玩一些棘手的qi :: _ val和qi :: _ 1游戏。 我真正想要的是
s = qi::repeat(1,2)[qi::digit]
[(
[](auto& parsed_number)
{
return parsed_number.size()==2 ?
parsed_number : std::string("0") + parsed_number;
}
]);
但这种方式不起作用
#include <boost/spirit/include/qi.hpp>
#include <vector>
#include <string>
#include <iostream>
namespace qi = boost::spirit::qi;
using V = std::vector<std::string>;
template<typename It, typename Skipper>
struct G: qi::grammar<It, V(), Skipper>
{
G(): G::base_type(v)
{
v = s % ',';
s = qi::repeat(1,2)[qi::digit];
}
private:
qi::rule<It, V(), Skipper> v;
qi::rule<It, std::string(), Skipper> s;
};
int main()
{
const std::string s = "1, 2, 3, 10, 15";
std::string::const_iterator beg(s.begin()), e;
G<decltype(beg), qi::space_type> g;
V R;
bool b = qi::phrase_parse(beg, e, g, qi::space, R);
if(!b){
std::cerr << "parsing failed\n";
return -1;
}
for(const auto& r: R) std::cout << r << '\n';
}
答案 0 :(得分:1)
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/fusion/include/at.hpp>
#include <vector>
#include <string>
#include <iostream>
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
namespace fusion= boost::fusion;
using V = std::vector<std::string>;
template<typename It, typename Skipper>
struct G: qi::grammar<It, V(), Skipper>
{
G(): G::base_type(v)
{
v = s % ',';
//s = qi::hold[qi::repeat(2)[qi::digit]]|(qi::attr('0') >> qi::digit);
//s = (&qi::repeat(2)[qi::digit] | qi::attr('0')) >> qi::repeat(1,2)[qi::digit];
//s = qi::as_string[qi::repeat(1,2)[qi::digit]] [qi::_val = phx::if_else(phx::size(qi::_1)==2,qi::_1,phx::val('0')+qi::_1)];
s = qi::as_string[qi::repeat(1,2)[qi::digit]]
[(
[](auto& parsed_number, auto& ctx)
{
fusion::at_c<0>(ctx.attributes) = parsed_number.size()==2 ?
parsed_number : '0' + parsed_number;
}
)];
}
private:
qi::rule<It, V(), Skipper> v;
qi::rule<It, std::string(), Skipper> s;
};
int main()
{
const std::string s = "1, 2, 3, 10, 15";
std::string::const_iterator beg(s.begin()), e;
G<decltype(beg), qi::space_type> g;
V R;
bool b = qi::phrase_parse(beg, e, g, qi::space, R);
if(!b){
std::cerr << "parsing failed\n";
return -1;
}
for(const auto& r: R) std::cout << r << '\n';
}
答案 1 :(得分:0)
这是您想要的吗?
#include <boost/spirit/include/qi.hpp>
#include <vector>
#include <string>
#include <iostream>
#include <boost/spirit/include/karma.hpp>
#include <iterator>
namespace qi = boost::spirit::qi;
namespace karma = boost::spirit::karma;
using SNT = long int;
using V = std::vector<SNT>;
template<typename It, typename Skipper>
struct G: qi::grammar<It, V(), Skipper>
{
G(): G::base_type(v)
{
v = s % ',';
s = qi::int_parser<SNT>(); /*Change to qi::int_parser<SNT,10,2> if you also only
* want to accept at least 2 digit decimals*/
}
private:
qi::rule<It, V(), Skipper> v;
qi::rule<It, SNT(), Skipper> s;
};
template<typename OutputIterator>
struct GG : karma::grammar<OutputIterator, V()> {
GG() : GG::base_type(start) {
start = karma::right_align(2,'0')[karma::int_generator<SNT>()] % '\n';
}
karma::rule<OutputIterator, V()> start;
};
int main()
{
const std::string s = "1, 2, 3, 10, 15";
std::string::const_iterator beg(s.begin()), e;
G<decltype(beg), qi::space_type> g;
V R;
bool b = qi::phrase_parse(beg, e, g, qi::space, R);
if(!b){
std::cerr << "parsing failed\n";
return EXIT_FAILURE;
}
for(const auto& r: R) std::cout << r << '\n';
std::string o{};
V O;
GG<std::back_insert_iterator<std::string>> gg;
b = karma::generate(std::back_inserter(o), gg, R);
if (!b)
throw std::runtime_error{"Generation failed"};
std::cout << o;
}