【问题标题】:Boost Spirit Qi Symbols default value and NULL value提升灵气符号默认值和NULL值
【发布时间】:2016-08-27 20:07:26
【问题描述】:

Boost Spirit qi::symbols 实现了一个键值对的映射:给一个字符串的一个键,它可以返回一个特定的值。我的问题是:

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

【问题讨论】:

    标签: c++ boost-spirit-qi


    【解决方案1】:

    您无法仅使用qi::symbols 完成您想要的。应该可以创建一个达到预期结果的 Spirit 终端/指令,但这样做会非常复杂,并且需要了解 qi::symbols 和相关类的内部工作原理,所以我认为这不是一个值得的方法。幸运的是,有一个非常简单的替代方案,使用 qi::attr(val),它是一个不消耗任何输入的解析器,将 val 公开为其属性并且总是成功。

    让我们看看所有三种情况:

    • 如果字符串在符号表中,则返回其关联值-&gt;只需使用sym
    • 如果字符串为空,则返回 1 -&gt; 只需使用 attr(1)
    • 如果字符串不在符号表中,则返回 4 -&gt; 此处您需要使用 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;
    }
    

    【讨论】:

    • 太棒了!完美的解决方案,详细的解释,快速的响应。非常感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-18
    • 2020-12-25
    • 2018-11-17
    • 2014-09-01
    相关资源
    最近更新 更多