2017-02-03 15 views
1

Я пытаюсь проанализировать числовое значение из строки с нечетными цифрами между ними. Можно ли это сделать с повышением духа? Например,Проанализируйте целое число с цифрами между ними с использованием boost spirit

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 Спасибо. Это все еще утомительно, и на самом деле не «использует дух» (просто интегрируется с ним). Ваш образец довольно интересный. Может быть более общим: 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])); 

[EDIT] Или без isdigit:

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

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

[EDIT 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_)); 

[EDIT 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);