代码之家  ›  专栏  ›  技术社区  ›  Max

Boost Spirit在空字符串输入时失败

  •  1
  • Max  · 技术社区  · 8 年前

    我试图解析以下字符串并提取括号内的部分。

    此字符串失败:

    _FIND('Something', '')_
    Should return
    part1 = 'Something'
    part2 = ''
    

    此字符串传递:

    _FIND('Something', '*')_
    Returns
    part1 = 'Something'
    part2 = '*'
    

    我假设问题在于“quoted\u字符串”

        find_parser() : find_parser::base_type(start)
        {
            using qi::lit;
            using qi::lexeme;
            using standard_wide::char_;
    
            /// simple quoted string.
            quoted_string %= lexeme['\'' >> +(char_ - '\'') >> '\''];
    
            start %=
                -(lit("$(")) // optional
                >> lit("_FIND")
                >> '('
                >> quoted_string
                >> -(',' >> quoted_string) // 2nd parameter optional
                >> ")_"
                >> -(lit(")")) // optional
                ;
        }
    

            quoted_string %= lexeme['\'' >> +(char_ - '\'') >> '\''];
            empty_quoted_string %= lexeme['\'' >> +(qi::space - '\'') >> '\''];
    
            start %=
                lit("_FIND")
                >> '('
                >> (quoted_string|empty_quoted_string)
                >> -(',' >> (quoted_string|empty_quoted_string)) // 2nd parameter optional
                >> ")_"
                ;
    

    我知道这一定是件简单的事,但我不能把我的手指放在上面。

    感谢您的任何意见、提示或提示。

    1 回复  |  直到 8 年前
        1
  •  1
  •   sehe    8 年前
      lexeme['\'' >> +(char_ - '\'') >> '\''];
    

    +p 意味着 p 必须 match one-or-more times . 如果必须接受空字符串,请使用 Kleene-star operator, which allows zero-or-more matches

      lexeme['\'' >> *(char_ - '\'') >> '\''];
    

    现场演示

    此外,不正确,其中 "$(_FIND('')" "_FIND('')" 将解析为“正确”

    Live On Coliru

    #include <boost/spirit/include/qi.hpp>
    #include <boost/fusion/adapted/std_pair.hpp>
    
    using Params = std::pair<std::string, std::string>;
    
    namespace qi = boost::spirit::qi;
    
    template <typename It> 
    struct find_parser : qi::grammar<It, Params()> {
        find_parser() : find_parser::base_type(start)
        {
            using namespace qi;
    
            start = skip(space) [ "$(" >> find >> ")" | find ];
    
            find
                = '_' >> lit("FIND") >> lit('(')
                >> quoted_string >> -(',' >> quoted_string) // 2nd parameter optional
                >> ')' >> '_'
                ;
    
            quoted_string = "'" >> *~char_("'") >> "'";
    
            BOOST_SPIRIT_DEBUG_NODES((start)(find)(quoted_string))
        }
    
      private:
        qi::rule<It, Params()> start;
    
        // rules with skipper
        qi::rule<It, Params(), qi::space_type> find;
    
        // implicit lexemes
        qi::rule<It, std::string()> quoted_string;
    };
    
    int main() {
        using It = std::string::const_iterator;
        find_parser<It> const p;
    
        for (std::string const input : {
                "_FIND('Something', 'Something else')_",
                "_ FIND('Something', 'Something else') _",
                "$(_FIND('Something', 'Something else')_)",
                "$( _FIND( 'Something', 'Something else' )_ )",
                // second arg empty
                "_FIND('Something', '')_",
                "_ FIND('Something', '') _",
                "$(_FIND('Something', '')_)",
                "$( _FIND( 'Something', '' )_ )",
                // optional args omitted
                "_FIND('Something')_",
                "_ FIND('Something') _",
                "$(_FIND('Something')_)",
                "$( _FIND( 'Something' )_ )",
                })
        {
            std::cout << "-------- " << input << " ------------\n";
    
            It f = input.begin(), l = input.end();
            Params parsed;
            if (parse(f, l, p, parsed))
                std::cout << "Parsed: '" << parsed.first << "', '" << parsed.second << "'\n";
            else
                std::cout << "Parsing failed\n";
    
            if (f!=l)
                std::cout << "  -- Remaining unparsed: '" << std::string(f,l) << "'\n";
        }
    }