代码之家  ›  专栏  ›  技术社区  ›  Brian Bi

如何获得boost.spirit数字解析器匹配的子字符串?

  •  0
  • Brian Bi  · 技术社区  · 5 年前

    我想用 qi::int_parser<int64_t> 解析整数值(它如何自动检查溢出、处理 INT_MIN 案件等)。但是,我也想得到 int_parser 匹配,因为如果它有多余的字符,我想打印一条警告消息( 、加号、前导零或以下情况 -0 ).

    我看到了 another answer 使用建议 qi::as_string ,但在这种情况下似乎行不通。以下是一些说明该问题的代码:

    #include <boost/phoenix/core.hpp>
    #include <boost/phoenix/operator.hpp>
    #include <boost/spirit/include/qi.hpp>
    #include <cstdint>
    #include <iostream>
    #include <string>
    int main() {
        namespace phx = boost::phoenix;
        namespace qi = boost::spirit::qi;
        using namespace std;
    
        std::string value_str;
        int64_t value;
        std::string test_str = "<+123>";
    
        const auto success = qi::parse(test_str.begin(), test_str.end(),
            qi::char_('<') >>
            qi::as_string[
                qi::int_parser<int64_t>{}[phx::ref(value) = qi::_1]
            ][phx::ref(value_str) = qi::_1] >>
            qi::char_('>')
        );
    
        std::cout << "success: " << success << '\n';
        std::cout << "value: " << value << '\n';
        std::cout << "matched substring: " << value_str << '\n';
    } 
    

    我想要的输出是

    success: 1
    value: 123
    matched substring: +123
    

    我得到的输出是

    success: 1
    value: 123
    matched substring: {
    

    (或其他垃圾)。解析int值工作得很好,但我不知道如何获取子字符串。

    0 回复  |  直到 5 年前
        1
  •  2
  •   doqtor    5 年前

    使用 qi::raw 在将其传递给 qi::as_string :

    qi::raw[qi::int_parser<int64_t>{}[phx::ref(value) = qi::_1]]

    结果:

    success: 1
    value: 123
    matched substring: +123
    
        2
  •  1
  •   sehe    5 年前

    我会简化使用一个适当的规则,这样你就不需要详细说明了 as_string 在解析表达式中。

    那里 在这种特殊情况下,它的工作方式出现了问题(应该作为bug报告给库维护人员)。但是,我可以通过添加一个 eps 解析器内部 raw 指令:

    r %= '<' >> raw[int64_[phx::ref(value) = _1] >> eps] >> '>';
    

    (另请注意,不需要解析括号 char_ ).

    Live On Coliru

    #include <boost/spirit/include/qi.hpp>
    #include <boost/spirit/include/phoenix.hpp>
    #include <iomanip>
    using namespace std::string_literals;
    
    int main()
    {
        namespace phx = boost::phoenix;
        namespace qi = boost::spirit::qi;
    
        qi::rule<std::string::const_iterator, std::string()> r;
    
        int64_t value;
        {
            using namespace qi;
            static const int_parser<int64_t> int64_{};
            r %= '<' >> raw[int64_[phx::ref(value) = _1] >> eps] >> '>';
        }
    
        using Lim = std::numeric_limits<decltype(value)>;
        for (std::string const test_str : {
                 "<+123>"s,
                 "<0123>"s,
                 "<0123>"s,
                 "<123>"s,
                 "<" + std::to_string(Lim::max()) + ">",
                 "<" + std::to_string(Lim::min()) + ">",
             })
        {
            std::string value_str;
    
            auto success
                = qi::parse(test_str.begin(), test_str.end(), r, value_str);
    
            std::cout << "success: " << std::boolalpha  << success << "\n";
            std::cout << "value: "             << value                  << "\n";
            std::cout << "matched substring: " << std::quoted(value_str) << "\n";
        }
    }
    

    印刷品

    success: true
    value: 123
    matched substring: "+123"
    success: true
    value: 123
    matched substring: "0123"
    success: true
    value: 123
    matched substring: "0123"
    success: true
    value: 123
    matched substring: "123"
    success: true
    value: 9223372036854775807
    matched substring: "9223372036854775807"
    success: true
    value: -9223372036854775808
    matched substring: "-9223372036854775808"
    

    奖金

    也封装“value”参数,这样就不用全局变量了:

    Live On Coliru

    #include <boost/spirit/include/qi.hpp>
    #include <boost/spirit/include/phoenix.hpp>
    #include <iomanip>
    using namespace std::string_literals;
    namespace phx = boost::phoenix;
    namespace qi = boost::spirit::qi;
    
    using It = std::string::const_iterator;
    using T = std::int64_t;
    
    struct Parser : qi::grammar<It, std::string(T&)> {
        Parser() : Parser::base_type(r) {
            r %= '<' >> qi::raw[ int64_[qi::_r1 = qi::_1] >> qi::eps ] >> '>';
        }
      private:
        qi::int_parser<T> int64_;
        qi::rule<It, std::string(T&)> r;
    };
    
    int main()
    {
        Parser const p;
        using Lim = std::numeric_limits<T>;
        for (std::string const test_str : {
                 "<+123>"s,
                 "<0123>"s,
                 "<0123>"s,
                 "<123>"s,
                 "<" + std::to_string(Lim::max()) + ">",
                 "<" + std::to_string(Lim::min()) + ">",
             })
        {
            std::string value_str;
            int64_t value;
    
            auto success
                = qi::parse(test_str.begin(), test_str.end(), p(phx::ref(value)), value_str);
    
            std::cout << "success: " << std::boolalpha  << success << "\n";
            std::cout << "value: "             << value                  << "\n";
            std::cout << "matched substring: " << std::quoted(value_str) << "\n";
        }
    }
    

    印刷:

    成功:真
    值:123
    匹配的子字符串:“+123”
    成功:真
    值:123
    匹配的子字符串:“0123”
    成功:真
    值:123
    匹配的子字符串:“0123”
    成功:真
    值:123
    匹配的子字符串:“123”
    成功:真
    价值:9223372036854775807
    匹配的子字符串:“9223372036854775807”
    成功:真
    数值:-922372036854775808
    匹配的子字符串:“-922372036854775808”