【问题标题】:Parsing float followed by string containing "e" character解析浮点数后跟包含“e”字符的字符串
【发布时间】:2019-02-01 18:37:51
【问题描述】:

我正在尝试解析这种类型的字符串

1.2e3ex
1.2e3 ex

并且已经设置

x3::float_ >> "ex"

很遗憾,解析失败

1ex

完整示例代码:

#include <iostream>
#include <boost/spirit/home/x3.hpp>
namespace x3 = boost::spirit::x3;

const auto parser = x3::float_ >> "em";

int main()
{
  std::string input = "1em";
  auto first = input.begin();
  auto last = input.end();

  float value{};
  bool result = x3::phrase_parse(first, last, parser, x3::blank, value);

  if(result)
  {
    if(first == last)
      std::cout << "parse succesful: " << value << '\n';
    else
      std::cout << "incomplete parse: " << value << '\n';
  }
  else
    std::cout << "parse unsuccesful\n";
}

live on Coliru 也可用。

看来我需要跳过一些障碍,

struct non_scientific_float_policy : x3::real_policies<float>
{
  template <typename Iterator>
  static bool parse_exp(Iterator& first, Iterator const& last)
  {
    return false;
  }
};

const auto non_scientific_float = x3::real_parser<float, non_scientific_float_policy>{};

provide an alternative:

const auto parser = non_scientific_float >> "em" | x3::float_ >> "em";

没有别的办法吗?

【问题讨论】:

  • 您能否提供minimal reproducible example 来说明问题所在?
  • @Nicol 第一个 coliru 链接就是这样。 "em" 中的 'e' 被float_ 解析器贪婪地占用,并且从未返回。
  • "第一个 coliru 链接就是这样。" MCVE 进入您的帖子,而不是链接。
  • @NicolBolas 关于 meta 的两个帖子,规则不成立。至少链接到我忽略的帮助中心中的位:“如果可以创建一个可以链接到的问题的实时示例(例如,在sqlfiddle.comjsbin.com),那么就这样做 - 而且将代码包含在您的问题本身中。并非每个人都可以访问外部站点,并且链接可能会随着时间的推移而中断。” Anyhoo,所有精彩的代码现在都可以供您观赏了。

标签: c++ boost c++17 boost-spirit boost-spirit-x3


【解决方案1】:

您可以通过调整实际策略 parse_exp 来解决此问题,即指数检测不仅需要[eE] 字符,还需要[eE][-+]?[0-9]

#include <iostream>
#include <boost/spirit/home/x3.hpp>
namespace x3 = boost::spirit::x3;

template <typename T>
struct alt_real_policies : x3::real_policies<T>
{
    template <typename Iterator>
    static bool parse_exp(Iterator& first, Iterator const& last)
    {
        Iterator save = first;
        if (x3::real_policies<T>::parse_exp(first, last)) {
            Iterator iter = first;
            if (x3::extract_int<x3::unused_type, 10, 1, 1>::call(iter, last, x3::unused))
                return true;
        }
        first = save;
        return false;
    }

};

const x3::real_parser<float, alt_real_policies<float>> altfloat;
const auto parser = altfloat >> "em";

int main()
{
    std::string input = "1em";
    auto first = input.begin();
    auto last = input.end();

    float value{};
    bool result = x3::phrase_parse(first, last, parser, x3::blank, value);

    if (result)
    {
        if (first == last)
            std::cout << "parse succesful: " << value << '\n';
        else
            std::cout << "incomplete parse: " << value << '\n';
    }
    else
        std::cout << "parse unsuccesful\n";
}

http://coliru.stacked-crooked.com/a/f60f334c960cb602

【讨论】:

  • 我喜欢。如果不是 extract_int 而是重用 parse_exp_n 会更好(引用记忆),我觉得
  • 这也是我的想法,但parse_exp_n 需要一个真正的价值;它还将解析所有数字并在数字溢出 int 时返回 false - 这将导致错误地忽略指数。
【解决方案2】:

您可以使用替代策略来进行指数的非贪婪解析。我能想到的最简单的是:

Live On Coliru

#include <boost/spirit/home/x3.hpp>
#include <iostream>
namespace x3 = boost::spirit::x3;

template <typename T>
struct no_exponent : x3::real_policies<T> {
    template <typename It>
        static bool parse_exp(It, It) { return false; }
};

x3::real_parser<double, no_exponent<double> > noexp_;

const auto parser = (x3::float_ | noexp_) >> "em";

int main() {
    std::string input = "-1.67em";
    auto first = input.begin();
    auto last = input.end();

    float value{};
    bool result = x3::phrase_parse(first, last, parser, x3::blank, value);

    if (result) {
        if (first == last)
            std::cout << "parse succesful: " << value << '\n';
        else
            std::cout << "incomplete parse: " << value << '\n';
    } else
    {
        std::cout << "parse unsuccesful\n";
    }
}

印刷:

parse succesful: -1.67

【讨论】:

  • @BenVoigt 哦。是的。那是隐藏得很好。我很高兴没有花很多时间。我可以详细说明我的拍摄稍微好一点的细微之处,但是,嘿。已经是 -1 了,何必呢。
  • 这是我的 +1。为什么你的表现更好:)?
  • 干杯。两个非常微妙/温和的点:以非科学为先的排序稍微不那么通用(想象一下,如果"em" 只是“e” - 这意味着3e7 不会被接受或留下7 未解析) .所以排序稍微好一点。另一件事是先验知识:我观察到real_parser&lt;float, ...&gt; 引入了不必要的错误,因此使用real_parser&lt;double, ...&gt; 是我的首选方法,甚至可以解析为浮点数。
猜你喜欢
  • 1970-01-01
  • 2014-10-13
  • 2015-03-15
  • 1970-01-01
  • 2021-06-30
  • 1970-01-01
  • 1970-01-01
  • 2011-12-19
  • 2012-05-04
相关资源
最近更新 更多