boost Spirit qi 整数和浮点数的数字解析

发布于 2024-09-07 03:45:09 字数 1924 浏览 3 评论 0原文

我试图理解以下结果。测试用例代码的

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <boost/spirit/home/support/context.hpp>
#include <boost/spirit/home/phoenix.hpp>
#include <boost/foreach.hpp>

#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
#include <vector>

namespace sp = boost::spirit;
namespace qi = boost::spirit::qi;
using namespace boost::spirit::ascii;

namespace fusion = boost::fusion;
namespace phoenix = boost::phoenix;

using phoenix::at_c;
using phoenix::push_back;
using phoenix::bind;

template <typename P>
void test_parser(
    char const* input, P const& p, bool full_match = true)
{
    using boost::spirit::qi::parse;

    char const* f(input);
    char const* l(f + strlen(f));
    if (parse(f, l, p) && (!full_match || (f == l)))
        std::cout << "ok" << std::endl;
    else
        std::cout << "fail" << std::endl;
}


int main() {

test_parser("+12345", qi::int_ ); //Ok
test_parser("+12345", qi::double_ - qi::int_ ); //failed, as expected
test_parser("+12345.34", qi::int_ );  // failed, as expected
test_parser("+12345.34", qi::double_ - qi::int_ );  //failed but it should be Ok!
};

动机是我想将数字“12345”匹配为整数,而不是浮点数。 '12345.34' 将匹配 double_ 而不会匹配 int_ 但倒数情况不成立; '12345' 匹配整数 (int_ ) 和浮点数 (double_ )。我尝试了 double_ - int_ ,但它成功地未能匹配“12345”。然而,我希望最后一个测试用例“12345.34”能够肯定地匹配 double_ - int_,但我得到的结果是无法匹配。

为什么会这样,以及如何获得一个仅匹配整数的解析器和另一个仅匹配浮点的解析器(如在 c 中,5.0 将被解释为浮点)

i am trying to make sense of the following result. The test case code is

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <boost/spirit/home/support/context.hpp>
#include <boost/spirit/home/phoenix.hpp>
#include <boost/foreach.hpp>

#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
#include <vector>

namespace sp = boost::spirit;
namespace qi = boost::spirit::qi;
using namespace boost::spirit::ascii;

namespace fusion = boost::fusion;
namespace phoenix = boost::phoenix;

using phoenix::at_c;
using phoenix::push_back;
using phoenix::bind;

template <typename P>
void test_parser(
    char const* input, P const& p, bool full_match = true)
{
    using boost::spirit::qi::parse;

    char const* f(input);
    char const* l(f + strlen(f));
    if (parse(f, l, p) && (!full_match || (f == l)))
        std::cout << "ok" << std::endl;
    else
        std::cout << "fail" << std::endl;
}


int main() {

test_parser("+12345", qi::int_ ); //Ok
test_parser("+12345", qi::double_ - qi::int_ ); //failed, as expected
test_parser("+12345.34", qi::int_ );  // failed, as expected
test_parser("+12345.34", qi::double_ - qi::int_ );  //failed but it should be Ok!
};

the motivation here is that i want to match numbers '12345' as integers and NEVER as floating points. '12345.34' will match double_ and never int_ but the reciprocal case is not true; '12345' matches both integers (int_ ) and floating point (double_ ). I tried double_ - int_ and it successfully failed to match '12345'. However my hope was that the last test case '12345.34' would positively match double_ - int_, but the result i get is fail to match.

Why this is so, and how do i get a parser that only matches integers and another that only matches floating points (like in c, 5.0 would be interpreted as floating point)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

好倦 2024-09-14 03:45:09

对于您的具体示例,我认为它实际上在 Boost Spirit 文档,位于 RealPolicies 专业化下。为了让事情对你来说更容易一些,我推出了一个快速的“真实”解析器,它只解析实数而不解析整数(或者至少它与你的简化示例一起工作):

template <typename T>
struct strict_real_policies : qi::real_policies<T>
{
    static bool const expect_dot = true;
};

qi::real_parser< double, strict_real_policies<double> > real;

你可以像使用任何其他解析器一样使用它(如 int_ 和 double_)。您可能需要添加:

#include <boost/spirit/include/qi_numeric.hpp>

才能编译。

For your specific example, I think it's actually described in the Boost Spirit documentation under RealPolicies Specialization. To make things a bit easier for you, I whipped out a quick "real" parser, that only parses real numbers and not integers(or at least it worked with your simplified examples):

template <typename T>
struct strict_real_policies : qi::real_policies<T>
{
    static bool const expect_dot = true;
};

qi::real_parser< double, strict_real_policies<double> > real;

And you can use this just like any other parser(like int_ and double_). You might have to add:

#include <boost/spirit/include/qi_numeric.hpp>

To get it to compile.

離殇 2024-09-14 03:45:09

double-not-int qi::double_ - qi::int_ 的问题是单个解析器不必匹配整个输入才能成功匹配。对于“+12345.34”,qi::double_ 对整个内容进行成功匹配,并且 qi::int 对“+12345”进行成功匹配,因此 qi::double_ - qi::int_ 是不匹配的。对于差分运算符,请考虑单独应用每个解析器,以及每个解析器是否存在有效匹配,甚至对于输入的第一部分也是如此。

您可以通过在 qi::int_ 之后要求某种边界来获得您想要的行为。当 qi::int_ 与 float 的第一部分匹配时,接下来的内容是有效的 float(例如,“+12345.34”上的 qi::int_ 匹配“+12345”,在流上留下“.34”)。因此,您可以对 float 进行否定前瞻:

int_rule %= qi::int_ >> !qi::double_;

double_rule %= qi::double_ - int_rule; 

或者

double_rule %= qi::double_ - (qi::int_ >> !qi::double_); 

!qi::double 对于空格和 eoi 也是如此,所以我认为这对于标准格式来说应该是非常通用的。但这不适用于科学记数法。

The problem with the double-not-int qi::double_ - qi::int_ is that an individual parser doesn't have to match the whole input to be a successful match. For "+12345.34", qi::double_ makes a successful match on the whole thing and qi::int makes a successful match on "+12345", so that qi::double_ - qi::int_ is a non-match. For difference operator, think about applying each parser separately and whether there is a valid match for each for even the first part of the input.

You can get the behavior you want by requiring some kind of boundary after qi::int_. What follows when an qi::int_ matches the first part of a float is a valid float (e.g. qi::int_ on "+12345.34" matches "+12345", leaving ".34" next on the stream). Therefore, you can do a negative look ahead for a float:

int_rule %= qi::int_ >> !qi::double_;

double_rule %= qi::double_ - int_rule; 

or

double_rule %= qi::double_ - (qi::int_ >> !qi::double_); 

!qi::double is also true for whitespace and eoi, so I think this should be pretty general for standard format. This won't work for scientific notation though.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文