2017-02-03 29 views
1

我想解析中间有非数字的字符串的数值。是否有可能以助推精神来做到这一点?例如,解析一个整数与非数字之间使用助推精神

std::string s = "AB1234xyz5678C9"; 
int x = 0; 
boost::spirit::qi::parse(s.begin(), s.end(), /* Magic Input */, x); 
// x will be equal 123456789 
+2

我不熟悉的开机::精神。你完全可以做到这一点:http://ideone.com/Fxdzg6 – Jonas

回答

4

一个黑客攻击的位:

weird_num = as_string[ skip(alpha) [+digit] ] [_val = stol_(_1) ]; 

这需要你去适应std::stol用于语义动作:

Live On Coliru

#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/phoenix.hpp> 

BOOST_PHOENIX_ADAPT_FUNCTION(long, stol_, std::stol, 1); 
namespace qi = boost::spirit::qi; 

int main() 
{ 
    std::string const s = "AB1234xyz5678C9"; 
    qi::rule<std::string::const_iterator, long()> weird_num; 

    { 
     using namespace qi; 
     weird_num = as_string[ skip(alpha) [+digit] ] [_val = stol_(_1) ]; 
    } 

    long x = 0; 
    if (boost::spirit::qi::parse(s.begin(), s.end(), weird_num, x)) 
     std::cout << "Got it: " << x << "\n"; 
} 

打印

Got it: 123456789 
+0

非常好。我正在考虑这个任务,但我的变体比你的更糟。 +1。 – ForEveR

+0

@ForEveR谢谢。它仍然很乏味,实际上并没有“使用Spirit”(只是与它整合)。你的样品很有趣。可以更通用:http://coliru.stacked-crooked.com/a/8b8240db04f8d003 :) – sehe

+0

这是非常好的,谢谢你,我不知道中间字符串是否可以删除。手工制作的循环逐一检查字符,然后乘以10应该会更快。 – alex

1

我认为可以轻松完成,但是,这是使用boost::spirit工作变种。

#include <string> 
#include <iostream> 
#include <boost/bind.hpp> 
#include <boost/spirit/include/qi.hpp> 

struct integer_collector 
{ 
public: 
    void collect(int v) const 
    { 
     stream << v; 
    } 

    int get() const 
    { 
     int result = 0; 
     stream >> result; 
     return result; 
    } 
private: 
    mutable std::stringstream stream; 
}; 

int main() 
{ 
    using namespace boost::spirit::qi; 
    std::string s = "AB1234xyz5678C9"; 
    integer_collector collector; 
    int x = 0; 
    boost::spirit::qi::parse(s.begin(), s.end(),  
    *(omit[*alpha] >> int_ >> omit[*alpha]) 
    [boost::bind(&integer_collector::collect, boost::ref(collector), 
    boost::placeholders::_1)]); 
    x = collector.get(); 
    std::cout << x << std::endl; 
} 

live

1

这里有一种方法:

namespace qi = boost::spirit::qi; 

std::string s = "AB1234xyz5678C9"; 
int x = 0; 
auto f = [&x](char c){ if (::isdigit(c)) x = x * 10 + (c - '0'); }; 

qi::parse(s.begin(), s.end(), +(qi::char_[f])); 

[编辑] 或者不ISDIGIT:

auto f = [&x](char c){ x = x * 10 + (c - '0'); }; 

qi::parse(s.begin(), s.end(), +(qi::char_("0-9")[f] | qi::char_)); 

[编辑2] 或者,没有拉姆达:

#include "boost\phoenix.hpp" 
... 

namespace phx=boost::phoenix; 

qi::parse(s.begin(), s.end(),+(qi::char_("0-9") 
     [phx::ref(x) = phx::ref(x) * 10 + qi::_1 - '0'] | qi::char_)); 

[编辑3] 或者,用递归规则:

qi::rule<std::string::iterator, int(int)> skipInt = 
    (qi::char_("0-9")[qi::_val = qi::_r1 * 10 + (qi::_1 - '0')] 
    | qi::char_[qi::_val = qi::_r1]) 
     >> -skipInt(qi::_val)[qi::_val = qi::_1]; 

qi::parse(s.begin(), s.end(), skipInt(0), x);