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

How to get the substring matched by a boost.spirit numeric parser?

我想使用 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 值工作正常,但我不知道如何获取子字符串。

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

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

结果:

success: 1
value: 123
matched substring: +123

我会使用适当的规则进行简化 - 这样您就不需要在解析表达式中拼出 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"

奖金

也封装“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";
    }
}

正在打印:

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"