【问题标题】:How to get the substring matched by a boost.spirit numeric parser?如何获取 boost.spirit 数字解析器匹配的子字符串?
【发布时间】:2021-02-26 02:28:47
【问题描述】:

我想使用qi::int_parser<int64_t> 来解析一个整数值(它自动检查溢出、处理INT_MIN 情况等非常方便)。但是,我还想获取int_parser 匹配的子字符串,因为如果它包含无关字符(ie、加号、前导零或大小写),我想打印一条警告消息-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 值工作得很好,但我不知道如何获取子字符串。

【问题讨论】:

    标签: c++ boost-spirit boost-spirit-qi


    【解决方案1】:

    在传递给qi::as_string之前使用qi::raw

    qi::raw[qi::int_parser&lt;int64_t&gt;{}[phx::ref(value) = qi::_1]]

    结果:

    success: 1
    value: 123
    matched substring: +123
    

    【讨论】:

      【解决方案2】:

      我会使用适当的规则进行简化 - 因此您无需在解析表达式中拼出 as_string

      在这种特殊情况下它的工作方式存在有问题(应将其作为错误报告给库维护者)。但是我可以通过在raw 指令中添加一个eps 解析器来解决它:

      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"
      

      奖金

      也封装“值”参数,所以你不要使用全局变量:

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

      印刷:

      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"
      

      【讨论】:

      • 添加了封装解析器并将“全局”变量替换为继承属性的奖励:coliru.stacked-crooked.com/a/261b66785a435acb
      • 如果没有eps,它实际上对我来说工作得很好(尽管我的实际用例与我在问题中显示的略有不同)。没有eps 会发生什么错误行为?
      • 是的,它应该可以在没有的情况下工作。 raw[] 将迭代器范围返回到所有匹配的主题。我得到了“+”(repro:coliru.stacked-crooked.com/a/10d08baf100f6595
      • 我怀疑这个错误是在你的 Boost 版本中,而不是我的。我的版本较旧。
      • 嘿,我对您的示例不太了解:您的规则r 如何知道从中间操作数(qi::raw 部分)传播合成属性?对不起,如果这是一个非常基本的问题。我昨天真的开始使用 Boost.Spirit。
      猜你喜欢
      • 2014-03-24
      • 1970-01-01
      • 1970-01-01
      • 2016-10-23
      • 2015-12-22
      • 1970-01-01
      • 2019-11-14
      • 2014-11-18
      • 2015-10-14
      相关资源
      最近更新 更多