2016-08-27 41 views
3

Boost Spirit qi :: symbols實現了鍵值對的映射:給出一個字符串的鍵,它可以返回一個特定的值。我的問題是:Boost Spirit Qi符號默認值和NULL值

1)對於空白字符串,是否可以返回默認值? (代碼中的Q1)

2)對於非空字符串或鍵值對映射中列出的鍵的字符串,是否可以返回表示鍵無效的值? (Q2代碼)

**以下代碼基於BOOST SPIRIT文檔。 **預先感謝您的任何建議。

#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; 
} 

回答

2

你只用qi::symbols就不能完成你想要的。應該可以創建一個Spirit終端/指令來實現所需的結果,但這樣做會非常複雜,需要知道qi::symbols和相關類的內部工作,所以我認爲這不是一個有價值的方法。幸運的是,使用qi::attr(val)是一個非常簡單的替代方案,不消耗任何輸入的解析器會將val作爲其屬性公開並始終成功。

讓我們來看看這三種情況下:

  • 如果字符串是在符號表中返回其關聯值->只使用sym
  • 如果字符串爲空返回1 ->只是用attr(1)
  • 如果該字符串不在符號表中返回4 ->這裏您需要使用attr(4)但這還不夠,因爲您還需要使用該字符串。如果我們假設字符串僅由字母組成,omit[+alpha]可以工作(omit丟棄文本,並且+確保至少有一個字母)。

你需要把這三個解析器的alternative parser牢記,在每種情況下,實際使用的解析器將是成功的第一個:

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

可能出現的問題:

  • 如果您在符號表中的字符串不夠複雜,您需要適當更改+alpha
  • 如果您使用的是隊長,你可能會需要使用omit[lexeme[+alpha]]停止貪婪+

全樣本(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。我完成了80%的工作。 – sehe

+0

太棒了!完美的解決方案,詳細的解釋,快速的反應非常感謝你。 – jianz

相關問題