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!
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 ];
#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)
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