2010-06-26 10 views
5

estoy tratando de dar sentido al siguiente resultado. El código de caso de prueba esboost spirit qi análisis numérico de números enteros y flotantes

#include <boost/config/warning_disable.hpp> 
#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/phoenix_core.hpp> 
#include <boost/spirit/include/phoenix_operator.hpp> 
#include <boost/spirit/include/phoenix_fusion.hpp> 
#include <boost/spirit/include/phoenix_stl.hpp> 
#include <boost/fusion/include/adapt_struct.hpp> 
#include <boost/variant/recursive_variant.hpp> 
#include <boost/spirit/home/support/context.hpp> 
#include <boost/spirit/home/phoenix.hpp> 
#include <boost/foreach.hpp> 

#include <iostream> 
#include <fstream> 
#include <string> 
#include <cstdlib> 
#include <vector> 

namespace sp = boost::spirit; 
namespace qi = boost::spirit::qi; 
using namespace boost::spirit::ascii; 

namespace fusion = boost::fusion; 
namespace phoenix = boost::phoenix; 

using phoenix::at_c; 
using phoenix::push_back; 
using phoenix::bind; 

template <typename P> 
void test_parser(
    char const* input, P const& p, bool full_match = true) 
{ 
    using boost::spirit::qi::parse; 

    char const* f(input); 
    char const* l(f + strlen(f)); 
    if (parse(f, l, p) && (!full_match || (f == l))) 
     std::cout << "ok" << std::endl; 
    else 
     std::cout << "fail" << std::endl; 
} 


int main() { 

test_parser("+12345", qi::int_); //Ok 
test_parser("+12345", qi::double_ - qi::int_); //failed, as expected 
test_parser("+12345.34", qi::int_); // failed, as expected 
test_parser("+12345.34", qi::double_ - qi::int_); //failed but it should be Ok! 
}; 

la motivación aquí es que quiero para que coincida con los puntos nunca como números flotantes '12345' como enteros y. '12345.34' coincidirá con double_ y never int_, pero el caso recíproco no es verdadero; '12345' coincide con enteros (int_) y coma flotante (double_). Probé double_ - int_ y falló al no coincidir con '12345'. Sin embargo, mi esperanza era que el último caso de prueba '12345.34' coincidiría positivamente con double_ - int_, pero el resultado obtenido no coincide.

Por qué esto es así, y cómo puedo obtener un analizador que sólo coincide con números enteros y otro que sólo coincide con puntos flotantes (como en C, 5,0 sería interpretado como punto flotante)

Respuesta

14

Para su ejemplo específico, creo que en realidad se describe en el Boost Spirit documentation bajo RealPolicies Especialización. Para hacer las cosas un poco más fácil para usted, Saqué un analizador rápido "real", que sólo analiza los números reales y no enteros (o, al menos, funcionó con sus ejemplos simplificados):

template <typename T> 
struct strict_real_policies : qi::real_policies<T> 
{ 
    static bool const expect_dot = true; 
}; 

qi::real_parser< double, strict_real_policies<double> > real; 

y se puede utilizar esto como cualquier otro analizador (como int_ y double_). Es posible que tenga que agregar:

#include <boost/spirit/include/qi_numeric.hpp> 

Para hacer que compile.

+0

+1 Esta es una mejor solución. – academicRobot

+0

gracias, esto funciona perfecto – lurscher

4

El problema con el doble not-int qi::double_ - qi::int_ es que un analizador individual no tiene que coincidir con la entrada completa para que sea una coincidencia exitosa. Para "+12345.34", qi :: double_ hace una coincidencia exitosa en todo el asunto y qi :: int hace una coincidencia exitosa en "+12345", por lo que qi::double_ - qi::int_ no coincide. Para el operador de diferencia, piense en aplicar cada analizador por separado y si hay una coincidencia válida para cada uno, incluso para la primera parte de la entrada.

Puede obtener el comportamiento que desea requiriendo algún tipo de límite después de qi :: int_. Lo que sigue cuando un qi :: int_ coincide con la primera parte de un float es un float válido (por ejemplo, qi :: int_ on "+12345.34" coincide con "+12345", dejando ".34" a continuación en el flujo). Por lo tanto, se puede hacer un aspecto negativo delante de un flotador:

int_rule %= qi::int_ >> !qi::double_; 

double_rule %= qi::double_ - int_rule; 

o

double_rule %= qi::double_ - (qi::int_ >> !qi::double_); 

!qi::double es también cierto para los espacios en blanco y EOI, así que creo que esto debe ser bastante general para el formato estándar. Sin embargo, esto no funcionará para la notación científica.

+0

ah, pensé que el operador A - B actuó como: dada una cadena N que coincide con A, si B coincide, entonces AB no coincidirá (pero esto es lo que mencionas, puede coincidir _part_ con B, no todo el asunto) así que no es muy intuitivo, pero ahora lo entiendo, ¡gracias! – lurscher

Cuestiones relacionadas