2016-08-27 2 views
3

Boost Spirit qi :: symbols implementiert eine Karte von Schlüssel-Wert-Paaren: Geben Sie einen Schlüssel einer Zeichenkette ein, sie kann einen bestimmten Wert zurückgeben. Meine Fragen sind:Boost Spirit Qi Symbole Standardwert und Nullwert

1) Ist es für eine leere Zeichenkette möglich, einen Standardwert zurückzugeben? (Q1 im Code)

2) Ist es für eine Zeichenfolge, die nicht eine leere Zeichenfolge oder die Schlüssel in der Zuordnung der Schlüssel/Wert-Paare ist, möglich, einen Wert zurückzugeben, der angibt, dass der Schlüssel ungültig ist? (Q2 im Code)

** Der folgende Code basiert auf dem BOOST SPIRIT-Dokument. ** Vielen Dank im Voraus für Anregungen.

#include <boost/spirit/include/support_utree.hpp> 
#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/phoenix_core.hpp> 
#include <boost/spirit/include/phoenix_operator.hpp> 
#include <boost/fusion/include/adapt_struct.hpp> 
#include <boost/assert.hpp> 
#include <iostream> 
#include <string> 
#include <cstdlib> 

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

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

int main() 
{ 
    using boost::spirit::qi::symbols; 

    symbols<char, int> sym; 
    sym.add 
     ("Apple", 1) 
     ("Banana", 2) 
     ("Orange", 3) 
    ; 

    int i; 
    test_parser_attr("Banana", sym, i); 
    std::cout << i << std::endl;  // 2 


    test_parser_attr("", sym, i);  // Q1: key is "", 
    std::cout << i << std::endl;  // would like it to be 1 as default 

    test_parser_attr("XXXX", sym, i); // Q2: key is other than "Apple"/"Banana"/"Orange", 
    std::cout << i << std::endl;  // would like it to be 4 

    return 0; 
} 

Antwort

2

Sie können nicht erreichen, was Sie nur ein qi::symbols mit wollen. Es sollte möglich sein, ein Spirit-Terminal/eine Direktive zu erstellen, die das gewünschte Ergebnis erzielt, aber dies wäre sehr komplex und erfordert Kenntnisse über das Innenleben von qi::symbols und verwandten Klassen, also halte ich es nicht für einen lohnenden Ansatz. Zum Glück gibt es eine wirklich einfache Alternative mit qi::attr(val), ein Parser, der keine Eingabe verbraucht, legt val als Attribut und ist immer erfolgreich.

Lassen Sie uns alle drei Fälle sehen:

  • , wenn die Zeichenfolge in der Tabelle Symbol ist der zugehörige Wert zurückgeben -> nur sym verwenden
  • , wenn die Zeichenfolge leer Rückkehr 1 -> verwenden nur attr(1)
  • wenn Die Zeichenfolge ist nicht in der Symboltabelle Return 4 -> hier müssen Sie attr(4) verwenden, aber das ist nicht genug, da Sie auch die Zeichenfolge verbrauchen müssen. Wenn wir annehmen, dass die Zeichenfolge nur aus Buchstaben besteht, könnte omit[+alpha] funktionieren (omit verwirft den Text und + stellt sicher, dass es mindestens einen Buchstaben gibt).

Sie müssen diese drei Parser in einer alternative parser unter Berücksichtigung setzen, dass der Parser tatsächlich in jedem Fall verwendet wird der erste sein, um erfolgreich zu sein:

sym | omit[+alpha] >> attr(4) | attr(1) 

Mögliche Probleme:

  • Wenn Ihre Nicht-in-Symbol-Tabellen-Zeichenfolge komplexer sein kann, müssen Sie +alpha entsprechend ändern.
  • Wenn Sie einen Skipper verwenden Sie wahrscheinlich omit[lexeme[+alpha]] zu stoppen, die gierig + verwenden müssen.

Beispiel anzeigen (Running on WandBox)

#include <iostream> 
#include <string> 

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


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

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

int main() 
{ 
    using boost::spirit::qi::symbols; 

    symbols<char, int> sym; 
    sym.add 
     ("Apple", 1) 
     ("Banana", 2) 
     ("Orange", 3) 
    ; 

    using boost::spirit::qi::attr; 
    using boost::spirit::qi::alpha; 
    using boost::spirit::qi::omit; 
    using boost::spirit::qi::lexeme; 

    //if the text is in the symbol table return the associated value 
    //else if the text is formed by letters (you could change this using for example `alnum`) and contains at least one, discard the text and return 4 
    //else return 1 
    boost::spirit::qi::rule<char const*,int()> symbols_with_defaults = sym | omit[+alpha] >> attr (4) | attr(1); 


    int i; 
    test_parser_attr("Banana", symbols_with_defaults, i); 
    std::cout << i << std::endl;  // 2 

    test_parser_attr("", symbols_with_defaults, i);  // Q1: key is "", 
    std::cout << i << std::endl;  // would like it to be 1 as default 

    test_parser_attr("XXXX", symbols_with_defaults, i); // Q2: key is other than "Apple"/"Banana"/"Orange", 
    std::cout << i << std::endl;  // would like it to be 4 

    std::vector<int> values; 
    test_parser_attr("<Banana>,<>,<xxxx>", ('<' >> symbols_with_defaults >> '>')%',', values); 
    for(int val : values) 
     std::cout << val << " "; // should be '2 1 4' 
    std::cout << std::endl; 

    return 0; 
} 
+0

+1. Ich habe zu 80% genau das geschrieben. – sehe

+0

Super! Perfekte Lösung, detaillierte Erklärung, schnelle Antwort. Vielen Dank. – jianz

Verwandte Themen