2011-03-18 18 views
8

estoy entre una profunda admiración sobre el impulso :: espíritu y la frustración eterna no entenderla;)espíritu Boost es demasiado codicioso

tengo problemas con las cadenas que son demasiado codiciosos y por lo tanto no coincide . Debajo de un ejemplo mínimo que no analiza, ya que la regla txt consume el final.

Más información acerca de lo que me gustaría hacer: el objetivo es analizar algunos pseudo-SQL y saltar espacios en blanco. En una declaración como

select foo.id, bar.id from foo, baz 

que necesito para tratar from como palabra clave especial. La regla es algo así como

"select" >> txt % ',' >> "from" >> txt % ',' 

pero es evidente que no funciona en bar.id from foo ve como un solo elemento.

#include <boost/spirit/include/qi.hpp> 
#include <iostream> 
namespace qi = boost::spirit::qi; 
int main(int, char**) { 
    auto txt = +(qi::char_("a-zA-Z_")); 
    auto rule = qi::lit("Hello") >> txt % ',' >> "end"; 
    std::string str = "HelloFoo,Moo,Bazend"; 
    std::string::iterator begin = str.begin(); 
    if (qi::parse(begin, str.end(), rule)) 
     std::cout << "Match !" << std::endl; 
    else 
     std::cout << "No match :'(" << std::endl; 
} 

Respuesta

10

aquí está mi versión, con los cambios marcados:

#include <boost/spirit/include/qi.hpp> 
#include <iostream> 
namespace qi = boost::spirit::qi; 
int main(int, char**) { 
    auto txt = qi::lexeme[+(qi::char_("a-zA-Z_"))];  // CHANGE: avoid eating spaces 
    auto rule = qi::lit("Hello") >> txt % ',' >> "end"; 
    std::string str = "Hello Foo, Moo, Baz end";  // CHANGE: re-introduce spaces 
    std::string::iterator begin = str.begin(); 
    if (qi::phrase_parse(begin, str.end(), rule, qi::ascii::space)) {   // CHANGE: used phrase_parser with a skipper 
    std::cout << "Match !" << std::endl << "Remainder (should be empty): '"; // CHANGE: show if we parsed the whole string and not just a prefix 
    std::copy(begin, str.end(), std::ostream_iterator<char>(std::cout)); 
    std::cout << "'" << std::endl; 
    } 
    else { 
    std::cout << "No match :'(" << std::endl; 
    } 
} 

Esto compila y se ejecuta con GCC 4.4.3 y aumentar 1.4something; Salida:

Match ! 
Remainder (should be empty): '' 

Mediante el uso de lexeme, se puede evitar el consumo de espacios de forma condicional, por lo que txt partidos hasta solamente un límite de palabra. Esto produce el resultado deseado: porque "Baz" no vaya seguida de una coma, y ​​txt no come espacios, nunca consumen accidentalmente "end".

De todos modos, no estoy 100% seguro de que esto es lo que está buscando, en particular, ¿falta str espacios faltantes como ejemplo ilustrativo, o está de alguna manera forzado a usar este formato (sin espacio)?

Nota al margen: si quiere asegurarse de haber analizado toda la cadena, agregue un cheque para ver si begin == str.end(). Como se indicó, el código informará una coincidencia aunque solo se haya analizado un prefijo no vacío de str.

Actualización: Agregado impresión sufijo.

+0

Gracias! Este lexema era lo que me estaba perdiendo. Usted estaba completamente derecho de agregar espacios (los dejé en el ejemplo tratando de tener algo mínimo, pero supongo que era más confuso que nada) –

+0

golpe de suerte;) Gracias. – phooji

Cuestiones relacionadas