c++ - 我正在使用 Boost.Spirit 来使用 boost::tuple 来检索解析器的属性,但没有成功
问题描述
看到这段代码:
using qi::int_;
using qi::phrase_parse;
using qi::_1;
using ascii::space;
std::string s = "50 43.3 77.44";
first = s.begin();
last = s.end();
boost::tuple<boost::optional<double>, boost::optional<int>> to;
bool r = phrase_parse(first, last,
(
double_ || int_
),
space, to); // r == true
auto a = to.get<0>(); // this works catches the 50 from the input
auto aa = *a;
auto b = to.get<1>(); // this does not work even though 43 is parsed correctly
auto bb = *b; // EXCEPTION
我尝试将这种奇怪的行为放在 spirit-general@lists.sourceforge.net 但没有人回答
代码非常小。如果有人尝试编译并运行它,我将不胜感激!
问候,胡安
解决方案
qi::double_ | qi::int_
解析备选方案,而不是序列。
换句话说,我希望您使用qi::double_ | qi::int_
来解析variant<double, int>
(或兼容)。
相反,用于qi::double_ >> qi::int_
解析tuple<double, int>
(或兼容)。
现在,double_ || int_
这是一个奇怪的序列:它是一个可选/替代序列:https ://www.boost.org/doc/libs/1_74_0/libs/spirit/doc/html/spirit/qi/reference/operator/sequential_or.html 。那么......你期望会发生什么?
目标是什么?
看起来您正在解析以空格分隔的数字。他们有3个。但是你解析成两个元组。用另一种顺序。其中两个分支冲突(任何整数都将解析为双精度数,而双精度数的整数部分可以解析为整数,正如您所熟知的,因为您声称“即使正确解析了 43”)。
我不知道你想要实现什么,因为大多数人永远不会说“43 被正确解析”,因为输入中没有数字 43(这只是 43.3 的一部分)。
让我们演示一下选项
因为很难猜出您在此处实际尝试解析的内容,所以让我们避免选择并仅演示从您的示例开始的所有方法:
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/optional/optional_io.hpp>
#include <boost/lexical_cast.hpp>
#include <iomanip>
namespace qi = boost::spirit::qi;
std::string const sample = "50 43.3 77.44";
template <typename T>
static std::string debug_string(T const& v, std::string const& sep = "") {
return boost::lexical_cast<std::string>(v) + sep;
}
template <typename... T>
static auto debug_string(std::tuple<T...> const& v, std::string const& sep = "") {
std::ostringstream oss;
oss << "( ";
auto out = [&oss](auto const&... elements) {
(oss << ... << debug_string(elements, " ")) << ")";
};
std::apply(out, v);
return oss.str() + sep;
}
template <typename Parser, typename... Attrs>
void demo_parse(Parser const& p, Attrs... attrs) {
auto first = sample.begin();
auto last = sample.end();
if (qi::phrase_parse(first, last, p, qi::space, attrs...)) {
((std::cout << "Parsed: ") << ... << debug_string(attrs, " ")) << "\n";
} else {
std::cout << "Parse failed\n";
}
if (first != last) {
std::cout << "Remaining input: " << std::quoted(std::string(first, last)) << "\n";
}
std::cout << "------------------------\n";
}
int main() {
std::cout << sample << "\n========================\n";
//// as a sequence
std::cout << "As a sequence" << "\n========================\n";
// note that int vs double input can be confusing:
auto parse_sequence = [](auto p) {
double d = 0; int i = 0;
demo_parse(p, d, i);
demo_parse(p, i, d);
demo_parse(p, std::tuple<double, int>{});
demo_parse(p, std::tuple<int, double>{});
demo_parse(p, std::tuple<boost::optional<double>, boost::optional<int> >{});
demo_parse(p, std::tuple<boost::optional<int>, boost::optional<double> >{});
};
parse_sequence(qi::int_ >> qi::double_);
parse_sequence(qi::double_ >> qi::int_);
// as an alternative
std::cout << "As alternatives" << "\n========================\n";
// - keeping in mind the confusion between double_ and int_, using
// strict_real_policies
qi::real_parser<double, qi::strict_real_policies<double> > sdouble_;
demo_parse(sdouble_ | qi::int_, boost::variant<int, double>{});
demo_parse(sdouble_ | qi::int_, boost::variant<double, int>{});
demo_parse(sdouble_ | qi::int_, boost::optional<boost::variant<int, double>>{});
// as alternative sequences
std::cout << "As alternative sequences" << "\n========================\n";
// - I don't know why this would be useful, and keep in mind the
// strict_real_policies again
demo_parse(sdouble_ || qi::int_, std::tuple<int, double>{});
demo_parse(sdouble_ || qi::int_, std::tuple<double, int>{});
demo_parse(sdouble_ || qi::int_, std::tuple<boost::optional<double>, boost::optional<int> >{});
std::cout << "Alternatives into variant type" << "\n========================\n";
demo_parse(sdouble_ || qi::int_, boost::variant<int, double>{});
demo_parse(sdouble_ || qi::int_, boost::variant<double, int>{});
demo_parse(sdouble_ || qi::int_, boost::optional<boost::variant<double, int>> {});
}
印刷
50 43.3 77.44
========================
As a sequence
========================
Parsed: 50 43
Remaining input: "77.44"
------------------------
Parsed: 50 43.299999999999997
Remaining input: "77.44"
------------------------
Parsed: ( 50 43 )
Remaining input: "77.44"
------------------------
Parsed: ( 50 43.299999999999997 )
Remaining input: "77.44"
------------------------
Parsed: ( 50 43 )
Remaining input: "77.44"
------------------------
Parsed: ( 50 43.3 )
Remaining input: "77.44"
------------------------
Parsed: 50 43
Remaining input: ".3 77.44"
------------------------
Parsed: 50 43
Remaining input: ".3 77.44"
------------------------
Parsed: ( 50 43 )
Remaining input: ".3 77.44"
------------------------
Parsed: ( 50 43 )
Remaining input: ".3 77.44"
------------------------
Parsed: ( 50 43 )
Remaining input: ".3 77.44"
------------------------
Parsed: ( 50 43 )
Remaining input: ".3 77.44"
------------------------
As alternatives
========================
Parsed: 50
Remaining input: "43.3 77.44"
------------------------
Parsed: 50
Remaining input: "43.3 77.44"
------------------------
Parsed: 50
Remaining input: "43.3 77.44"
------------------------
As alternative sequences
========================
Parsed: ( 0 50 )
Remaining input: "43.3 77.44"
------------------------
Parsed: ( 0 50 )
Remaining input: "43.3 77.44"
------------------------
Parsed: ( -- 50 )
Remaining input: "43.3 77.44"
------------------------
Alternatives into variant type
========================
Parsed: 0
Remaining input: "43.3 77.44"
------------------------
Parsed: 0
Remaining input: "43.3 77.44"
------------------------
Parsed: --
Remaining input: "43.3 77.44"
------------------------
或者也许:理智选项#1
这可能是压倒性的,所以这就是我认为你可能一直在追求的:只需解析一个 int-or-double 序列:
// #define BOOST_SPIRIT_DEBUG
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/include/qi.hpp>
#include <iomanip>
namespace qi = boost::spirit::qi;
std::string const sample = "50 43.3 77.44";
using It = std::string::const_iterator;
int main() {
std::cout << sample << "\n========================\n";
using Value = boost::variant<double, int>;
using Values = std::vector<Value>;
qi::real_parser<double, qi::strict_real_policies<double> > sdouble_;
qi::rule<It, Value()> double_or_int = sdouble_ | qi::int_;
BOOST_SPIRIT_DEBUG_NODE(double_or_int);
auto first = sample.begin();
auto last = sample.end();
Values values;
if (qi::phrase_parse(first, last, *double_or_int, qi::space, values)) {
std::cout << "Parsed:";
for (auto v : values)
std::cout << " " << v;
std::cout << "\n";
} else {
std::cout << "Parse failed\n";
}
if (first != last) {
std::cout << "Remaining input: " << std::quoted(std::string(first, last)) << "\n";
}
}
印刷
50 43.3 77.44
========================
Parsed: 50 43.3 77.44
理智(?)选项#2
也许线索在于“43被正确解析”的说法的奇怪之处。如果 43 被“正确”解析,则表示句点(“.”)不是小数分隔符。那么也许您想解析“1 2 . 3 4 . 5 6 . 7 8” 样式输入?
#define BOOST_SPIRIT_DEBUG
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/include/qi.hpp>
#include <iomanip>
namespace qi = boost::spirit::qi;
std::string const sample = "50 43.3 77.44";
using It = std::string::const_iterator;
int main() {
std::cout << sample << "\n========================\n";
auto first = sample.begin();
auto last = sample.end();
using Pair = std::pair<int, int>;
std::vector<Pair> values;
if (qi::phrase_parse(first, last, (qi::int_ >> qi::int_) % '.', qi::space, values)) {
std::cout << "Parsed:";
for (auto [a,b] : values)
std::cout << " (" << a << " " << b << ")";
std::cout << "\n";
} else {
std::cout << "Parse failed\n";
}
if (first != last) {
std::cout << "Remaining input: " << std::quoted(std::string(first, last)) << "\n";
}
}
印刷
50 43.3 77.44
========================
Parsed: (50 43) (3 77)
Remaining input: ".44"
推荐阅读
- google-apps-script - 显示错误的帐户
- bash - 使用 kubectl exec 获取语法错误,因为无法使用 TTY
- python - 如何计算列的唯一值并将每个值附加到字典中?
- python - 获取熊猫数据框中列的先前非 NaN 值以进行计算
- typescript - 使用 ts-loader 时解决类型依赖的问题,但不使用 tsc
- reactjs - 在我的 react-navigation/material-bottom-tabs 上添加通知计数器徽章
- angular - 防止 Angular Material 自动完成溢出页面容器
- android - 如何在 React Native 中制作 Android 手电筒
- python - 将小数字转换为从 0 到 10 的范围
- json - Chrome 83 开发工具“网络预览”选项卡应显示格式化的 JSON 响应时为空白