2017-02-03 66 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);