How to parse possibly missing unsigned integers with boost::spirit?

35 Views Asked by At

I need to parse two unsigned integers separated by white spaces into two std::optionals. One or both could be nans. For example valid inputs: "123 456" or "123 nan" or "nan 456" or "nan nan". What would be the most elegant rule for this? Thanks!

1

There are 1 best solutions below

0
sehe On BEST ANSWER

Assuming some things like,

  • an attribute type like

    using Pair = std::pair<std::optional<int>, std::optional<int>>;
    
  • using Spirit Qi

  • not desiring case-insensitivity

  • requiring full input to be consumed

  • requiring two tokens in the input always, with space only required when ambiguous (e.g. 1nan is fine without whitespace)

I'd suggest something like

auto optint = qi::copy(qi::int_ | "nan");
qi::rule<It, Pair()> p = qi::skip(qi::space) [ optint >> optint ];

Demo

Live On Coliru

#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/adapted/std_pair.hpp>
#include <optional>
#include <iomanip>
namespace qi = boost::spirit::qi;

using Pair = std::pair<std::optional<int>, std::optional<int>>;
using It   = std::string::const_iterator;

template <typename T> std::string display(std::optional<T> const& v) {
    return v? std::to_string(v.value()) : "nullopt";
}

static inline std::ostream& operator<<(std::ostream& os, Pair const& pair) {
    return os << "(" << display(pair.first) << ", " << display(pair.second) << ")";
}

int main() {
    auto optint = qi::copy(qi::int_ | "nan");
    qi::rule<It, Pair()> p = qi::skip(qi::space) [ optint >> optint ];

    for (std::string const input : {"123 456", "123 nan", "nan 456", "nan nan"}) {
        Pair parsed;
        if (parse(begin(input), end(input), p >> qi::eoi, parsed)) {
            std::cout << quoted(input) << " -> " << parsed << std::endl;
        } else {
            std::cout << quoted(input) << " -> Did not parse" << std::endl;
        }
    }
}

Printing

"123 456" -> (123, 456)
"123 nan" -> (123, nullopt)
"nan 456" -> (nullopt, 456)
"nan nan" -> (nullopt, nullopt)

BONUS

The same program in X3: https://coliru.stacked-crooked.com/a/92fb99cff768bb6f, printing

"123 456" -> (123, 456)
"123 nan" -> (123, nullopt)
"nan 456" -> (nullopt, 456)
"nan nan" -> (nullopt, nullopt)
"123nan" -> (123, nullopt)
"nan456" -> (nullopt, 456)

Requiring at least a single separating whitespace: https://coliru.stacked-crooked.com/a/1430e6be4727bff2, printing

"123 456" -> (123, 456)
"123 nan" -> (123, nullopt)
"nan 456" -> (nullopt, 456)
"nan nan" -> (nullopt, nullopt)
"123nan" -> Did not parse
"nan456" -> Did not parse