我正在尝试(还)使用从日志中解析的数据填充几个向量。关键是尽可能快速有效地做到这一点,所以我想只收集一遍中的所有数据(而不是"或者#34;规则之间)。
我发现了下一个问题:
1)每次我使用精神并且它没有按预期工作时,我发现自己完全失去了并且尝试了两个小时的测试和错误。是否有任何调试指令可以提供有关出错的提示?
2)我使用凤凰构造的方式有效吗?我的意思是,它可以像我在代码中所做的那样用来避免使用符号表吗?
3)有没有办法获取规则的信息并将其用于另一个规则?我尝试过使用phoenix :: ref,但在使用BOOST_FUSION_ADAPT_STRUCT时会混淆数据。
4)我是否因此而使用代码进行深度错误?我的意思是,我是否应该使用包含自动规则的语法,或者只是简化使用两个规则,用于" location"以及其他用于" location + event"然后用凤凰?
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/repository/include/qi_seek.hpp>
#include <boost/phoenix/phoenix.hpp>
#include <cstring> // strlen
typedef char const* It;
enum kind { SLOPE, GEAR };
struct Location {
int driver;
double time;
double vel;
double km;
std::string date;
std::string road;
};
struct Event {
int event;
double time;
double value;
};
BOOST_FUSION_ADAPT_STRUCT(Location, date, time, driver, vel, road, km)
BOOST_FUSION_ADAPT_STRUCT(Event, event, value)//Same "time" as its previous "Location" header. Please do not adapt "time" unless necesssary.
//They shall be defined in another compilation unit and defined as extern in production code. Please do not insert within dispatcher struct.
std::vector<Location> container1;
std::vector<Event> container2;
struct dispatcher
{
static void add(const Location& loc) { container1.push_back(loc); }
static void add(const Event& ev) { container2.push_back(ev); }
};
namespace qi = boost::spirit::qi;
namespace px = boost::phoenix;
namespace boost { namespace spirit { namespace traits
{
template <> struct is_container<dispatcher> : std::true_type { };
template <> struct container_value<dispatcher>
{
typedef boost::variant<Location, Event> type;
};
template <typename T> struct push_back_container<dispatcher, T>
{
struct Visitor
{
typedef void result_type;
template <typename U> void operator()(U const& ev) const { dispatcher::add(ev); }
};
static bool call(dispatcher& log, T const& attribute)
{
boost::apply_visitor(Visitor(), attribute);
return true;
}
};
} } }
void parse_test_1(It b, It e) {
using namespace qi;
auto date = copy(
repeat(4)[digit] >> '-' >> repeat(3)[alpha] >> '-' >> repeat(2)[digit] >> ' ' >>
repeat(2)[digit] >> ':' >> repeat(2)[digit] >> ':' >> repeat(2)[digit] >> '.' >> +digit);
qi::rule<It, Event()> slope = lit(" - SLOPE: ")[px::construct<int>(kind::SLOPE)] >> double_;
qi::rule<It, Event()> gear = lit(" - GEAR: ")[px::construct<int>(kind::GEAR)] >> double_;
qi::rule<It, Location()> line = '[' >> raw[date] >> "] - "
>> double_ >> " s"
>> " => Driver: " >> int_
>> " - Speed: " >> double_
>> " - Road: " >> raw[+graph]
>> " - Km: " >> double_
>> -(slope | gear)
>> (eol | eoi);
parse(b, e, *boost::spirit::repository::qi::seek[line], dispatcher());
}
void parse_test_2(It b, It e) {
using namespace qi;
double t = 0;
auto date = copy(
repeat(4)[digit] >> '-' >> repeat(3)[alpha] >> '-' >> repeat(2)[digit] >> ' ' >>
repeat(2)[digit] >> ':' >> repeat(2)[digit] >> ':' >> repeat(2)[digit] >> '.' >> +digit);
qi::rule<It, Event()> slope = lit(" - SLOPE: ")[px::construct<int>(kind::SLOPE)] >> double_;
qi::rule<It, Event()> gear = lit(" - GEAR: ")[px::construct<int>(kind::GEAR)] >> double_;
qi::rule<It, Location()> line = '[' >> raw[date] >> "] - "
>> double_ >> " s"
>> " => Driver: " >> int_
>> " - Speed: " >> double_
>> " - Road: " >> raw[+graph]
>> " - Km: " >> double_
>> -(slope | gear)
>> (eol | eoi);
parse(b, e, *line, dispatcher());
}
//Not all the lines will match the parser!
static char input1[] =
"[2018-Mar-13 13:13:59.580482] - 0.200 s => Driver: 0 - Speed: 0.0 - Road: A-11 - Km: 90.0 - SLOPE: 5.5\n\
[2018-Mar-13 13:14:01.170203] - 1.790 s => Driver: 0 - Speed: 0.0 - Road: A-11 - Km: 90.0 - GEAR: 1\n\
[2018-Mar-13 13:14:01.170203] - 1.790 s => Driver: 0 - Speed: 0.1 - Road: A-11 - Km: 90.0\n\
[2018-Mar-13 13:14:01.170203] - 1.790 s => I do not care about this line\n\
[2018-Mar-13 13:14:01.819966] - 2.440 s => Driver: 0 - Speed: 0.1 - Road: A-11 - Km: 90.0\n\
[2018-Mar-13 13:14:01.170203] - 2.440 s => Neither I do about this other line\n\
[2018-Mar-13 13:15:01.819966] - 3.440 s => Driver: 0 - Speed: 0.2 - Road: A-11 - Km: 90.0 - SLOPE: 10\n";
static const size_t len1 = strlen(input1);
//All the lines shall match the parser!
static char input2[] =
"[2018-Mar-13 13:13:59.580482] - 0.200 s => Driver: 0 - Speed: 0.0 - Road: A-11 - Km: 90.0 - SLOPE: 5.5\n\
[2018-Mar-13 13:14:01.170203] - 1.790 s => Driver: 0 - Speed: 0.0 - Road: A-11 - Km: 90.0 - GEAR: 1\n\
[2018-Mar-13 13:14:01.170203] - 1.790 s => Driver: 0 - Speed: 0.1 - Road: A-11 - Km: 90.0\n\
[2018-Mar-13 13:14:01.819966] - 2.440 s => Driver: 0 - Speed: 0.1 - Road: A-11 - Km: 90.0\n\
[2018-Mar-13 13:15:01.819966] - 3.440 s => Driver: 0 - Speed: 0.2 - Road: A-11 - Km: 90.0 - SLOPE: 10\n";
static const size_t len2 = strlen(input2);
int main()
{
parse_test_1(input1, input1+len1);
std::cout << "TEST 1:\n";
std::cout << "Locations:\n";
std::for_each(std::begin(container1), std::end(container1), [](const Location& loc)
{
std::cout << "[" << loc.date << "] - " << loc.time << " s => Driver: " << loc.driver << " - Speed: " << loc.vel << " - Road: " << loc.road << " - Km: " << loc.km << std::endl;
});
std::cout << "Events:\n";
std::for_each(std::begin(container2), std::end(container2), [](const Event& ev)
{
std::cout << ev.time << " s => EVENT(" << ev.event << ") : " << ev.value << std::endl;
});
container1.clear();
container2.clear();
parse_test_2(input2, input2+len2);
std::cout << "\nTEST 2:\n";
std::cout << "Locations:\n";
std::for_each(std::begin(container1), std::end(container1), [](const Location& loc)
{
std::cout << "[" << loc.date << "] - " << loc.time << " s => Driver: " << loc.driver << " - Speed: " << loc.vel << " - Road: " << loc.road << " - Km: " << loc.km << std::endl;
});
std::cout << "Events:\n";
std::for_each(std::begin(container2), std::end(container2), [](const Event& ev)
{
std::cout << ev.time << " s => EVENT(" << ev.event << ") : " << ev.value << std::endl;
});
return 0;
}
结果:预期的结果应该是这个:
TEST 1:
Locations:
[2018-Mar-13 13:13:59.580482] - 0.2 s => Driver: 0 - Speed: 0 - Road: A-11 - Km: 90
[2018-Mar-13 13:14:01.170203] - 1.79 s => Driver: 0 - Speed: 0 - Road: A-11 - Km: 90
[2018-Mar-13 13:14:01.170203] - 1.79 s => Driver: 0 - Speed: 0.1 - Road: A-11 - Km: 90
[2018-Mar-13 13:14:01.819966] - 2.44 s => Driver: 0 - Speed: 0.1 - Road: A-11 - Km: 90
[2018-Mar-13 13:15:01.819966] - 3.44 s => Driver: 0 - Speed: 0.2 - Road: A-11 - Km: 90
Events:
0.2 s => EVENT(0): 5.5
1.79 s => EVENT(1): 1
3.44 s => EVENT(0): 10
TEST 2:
Locations:
[2018-Mar-13 13:13:59.580482] - 0.2 s => Driver: 0 - Speed: 0 - Road: A-11 - Km: 90
[2018-Mar-13 13:14:01.170203] - 1.79 s => Driver: 0 - Speed: 0 - Road: A-11 - Km: 90
[2018-Mar-13 13:14:01.170203] - 1.79 s => Driver: 0 - Speed: 0.1 - Road: A-11 - Km: 90
[2018-Mar-13 13:14:01.819966] - 2.44 s => Driver: 0 - Speed: 0.1 - Road: A-11 - Km: 90
[2018-Mar-13 13:15:01.819966] - 3.44 s => Driver: 0 - Speed: 0.2 - Road: A-11 - Km: 90
Events:
0.2 s => EVENT(0): 5.5
1.79 s => EVENT(1): 1
3.44 s => EVENT(0): 10
答案 0 :(得分:1)
首先关闭:我在that answer中提供了全部,在&#34;分隔带有特征的向量&#34;。唯一的区别似乎是您使
LogEvents
成员全局变量(ick)的类型和事实。
转到您的问题代码:
parse(b, e, *boost::spirit::repository::qi::seek[line], dispatcher());
你为什么要把调度员送到那里? Dispatcher不是兼容属性(实际上只有静态非数据成员)。
所以,让我们把它修复为一个理智的数据结构(而不是全局变量):
struct ParsedData
{
std::vector<Location> _locations;
std::vector<Event> _events;
void add(const Location& loc) { _locations.push_back(loc); }
void add(const Event& ev) { _events.push_back(ev); }
};
请注意容器aren't global any more和have proper names。
boost::spirit::traits
专精是相同的( mutatis mutandis ),除了我们现在有一个数据实例,所以我们绑定它(再次,如the original example linked above, line 52中所示,所以让& #39; s修复用法:
ParsedData data;
parse(b, e, *boost::spirit::repository::qi::seek[line], data);
return data;
从这里开始,这一切都奏效了。
注意:
std::string
)没有理由复制所有代码并命名所有内容_1
或_2
。我做了主要的:
int main() {
do_test("TEST 1", input1, parse_test_1);
do_test("TEST 2", input2, parse_test_2);
}
没有理由将for_each
与lambda一起使用,其中ranged-for就足够了。这是do_test
:
void do_test(std::string caption, std::string const& input, ParsedData(*f)(It,It)) {
ParsedData const data = f(input.begin(), input.end());
std::cout << caption << ":\n";
std::cout << "Locations:\n";
for (Location const& loc : data._locations) {
std::cout << "[" << loc.date << "] - " << loc.time << " s => Driver: " << loc.driver << " - Speed: " << loc.vel << " - Road: " << loc.road << " - Km: " << loc.km << std::endl;
}
std::cout << "Events:\n";
for (Event const& ev : data._events) {
std::cout << " EVENT(" << ev.event << ") : " << ev.value << std::endl;
}
}
我从time
删除了Event
成员,因为它未被使用。
<强> Live On Coliru 强>
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/repository/include/qi_seek.hpp>
#include <boost/phoenix/phoenix.hpp>
#include <cstring> // strlen
typedef std::string::const_iterator It;
enum kind { SLOPE, GEAR };
struct Location {
int driver;
double time;
double vel;
double km;
std::string date;
std::string road;
};
struct Event {
int event;
double value;
};
BOOST_FUSION_ADAPT_STRUCT(Location, date, time, driver, vel, road, km)
BOOST_FUSION_ADAPT_STRUCT(Event, event, value)
struct ParsedData {
std::vector<Location> _locations;
std::vector<Event> _events;
void add(const Location& loc) { _locations.push_back(loc); }
void add(const Event& ev) { _events.push_back(ev); }
};
namespace qi = boost::spirit::qi;
namespace px = boost::phoenix;
namespace boost { namespace spirit { namespace traits {
template <> struct is_container<ParsedData> : std::true_type {};
template <> struct container_value<ParsedData> { typedef boost::variant<Location, Event> type; };
template <typename T> struct push_back_container<ParsedData, T> {
struct Visitor {
ParsedData &data;
typedef void result_type;
template <typename U> void operator()(U const &ev) const { data.add(ev); }
};
static bool call(ParsedData &log, T const &attribute) {
boost::apply_visitor(Visitor{ log }, attribute);
return true;
}
};
} } } // namespace boost::spirit::traits
ParsedData parse_test_1(It b, It e) {
using namespace qi;
auto date = copy(
repeat(4)[digit] >> '-' >> repeat(3)[alpha] >> '-' >> repeat(2)[digit] >> ' ' >>
repeat(2)[digit] >> ':' >> repeat(2)[digit] >> ':' >> repeat(2)[digit] >> '.' >> +digit);
qi::rule<It, Event()> slope = lit(" - SLOPE: ")[px::construct<int>(kind::SLOPE)] >> double_;
qi::rule<It, Event()> gear = lit(" - GEAR: ")[px::construct<int>(kind::GEAR)] >> double_;
qi::rule<It, Location()> line = '[' >> raw[date] >> "] - "
>> double_ >> " s"
>> " => Driver: " >> int_
>> " - Speed: " >> double_
>> " - Road: " >> raw[+graph]
>> " - Km: " >> double_
>> -(slope | gear)
>> (eol | eoi);
ParsedData data;
parse(b, e, *boost::spirit::repository::qi::seek[line], data);
return data;
}
ParsedData parse_test_2(It b, It e) {
using namespace qi;
auto date = copy(
repeat(4)[digit] >> '-' >> repeat(3)[alpha] >> '-' >> repeat(2)[digit] >> ' ' >>
repeat(2)[digit] >> ':' >> repeat(2)[digit] >> ':' >> repeat(2)[digit] >> '.' >> +digit);
qi::rule<It, Event()> slope = lit(" - SLOPE: ")[px::construct<int>(kind::SLOPE)] >> double_;
qi::rule<It, Event()> gear = lit(" - GEAR: ")[px::construct<int>(kind::GEAR)] >> double_;
qi::rule<It, Location()> line = '[' >> raw[date] >> "] - "
>> double_ >> " s"
>> " => Driver: " >> int_
>> " - Speed: " >> double_
>> " - Road: " >> raw[+graph]
>> " - Km: " >> double_
>> -(slope | gear)
>> (eol | eoi);
ParsedData data;
parse(b, e, *line, data);
return data;
}
//Not all the lines will match the parser!
static std::string const input1 =
"[2018-Mar-13 13:13:59.580482] - 0.200 s => Driver: 0 - Speed: 0.0 - Road: A-11 - Km: 90.0 - SLOPE: 5.5\n\
[2018-Mar-13 13:14:01.170203] - 1.790 s => Driver: 0 - Speed: 0.0 - Road: A-11 - Km: 90.0 - GEAR: 1\n\
[2018-Mar-13 13:14:01.170203] - 1.790 s => Driver: 0 - Speed: 0.1 - Road: A-11 - Km: 90.0\n\
[2018-Mar-13 13:14:01.170203] - 1.790 s => I do not care about this line\n\
[2018-Mar-13 13:14:01.819966] - 2.440 s => Driver: 0 - Speed: 0.1 - Road: A-11 - Km: 90.0\n\
[2018-Mar-13 13:14:01.170203] - 2.440 s => Neither I do about this other line\n\
[2018-Mar-13 13:15:01.819966] - 3.440 s => Driver: 0 - Speed: 0.2 - Road: A-11 - Km: 90.0 - SLOPE: 10\n";
//All the lines shall match the parser!
static std::string const input2 =
"[2018-Mar-13 13:13:59.580482] - 0.200 s => Driver: 0 - Speed: 0.0 - Road: A-11 - Km: 90.0 - SLOPE: 5.5\n\
[2018-Mar-13 13:14:01.170203] - 1.790 s => Driver: 0 - Speed: 0.0 - Road: A-11 - Km: 90.0 - GEAR: 1\n\
[2018-Mar-13 13:14:01.170203] - 1.790 s => Driver: 0 - Speed: 0.1 - Road: A-11 - Km: 90.0\n\
[2018-Mar-13 13:14:01.819966] - 2.440 s => Driver: 0 - Speed: 0.1 - Road: A-11 - Km: 90.0\n\
[2018-Mar-13 13:15:01.819966] - 3.440 s => Driver: 0 - Speed: 0.2 - Road: A-11 - Km: 90.0 - SLOPE: 10\n";
void do_test(std::string caption, std::string const& input, ParsedData(*f)(It,It)) {
ParsedData const data = f(input.begin(), input.end());
std::cout << caption << ":\n";
std::cout << "Locations:\n";
for (Location const& loc : data._locations) {
std::cout << "[" << loc.date << "] - " << loc.time << " s => Driver: " << loc.driver << " - Speed: " << loc.vel << " - Road: " << loc.road << " - Km: " << loc.km << std::endl;
}
std::cout << "Events:\n";
for (Event const& ev : data._events) {
std::cout << " EVENT(" << ev.event << ") : " << ev.value << std::endl;
}
}
int main() {
do_test("TEST 1", input1, parse_test_1);
do_test("TEST 2", input2, parse_test_2);
}
当您希望Event
规则(斜率/齿轮)匹配或合成属性时,我不清楚。我也不清楚为什么那些是可选的(没有那部分,一条线的位置部分不可能匹配)。
此外,由
等规则公开的自然属性qi::rule<It, Location()> line = '[' >> raw[date] >> "] - "
>> double_ >> " s"
>> " => Driver: " >> int_
>> " - Speed: " >> double_
>> " - Road: " >> raw[+graph]
>> " - Km: " >> double_
>> -(slope | gear)
>> (eol | eoi);
位置是否包含额外字段:
struct Location {
int driver;
double time;
double vel;
double km;
std::string date;
std::string road;
boost::optional<Event> event;
};
BOOST_FUSION_ADAPT_STRUCT(Event, event, value)
BOOST_FUSION_ADAPT_STRUCT(Location, date, time, driver, vel, road, km, event)
这些规则很奇怪:
qi::rule<It, Event()> slope = lit(" - SLOPE: ")[px::construct<int>(kind::SLOPE)] >> double_;
qi::rule<It, Event()> gear = lit(" - GEAR: ")[px::construct<int>(kind::GEAR)] >> double_;
为什么不使用symbols
approach exactly as I showed in the linked answer (line 57/98)?如果你坚持这样做&#34;笨拙&#34;,请不使用语义操作(Boost Spirit: "Semantic actions are evil"?),但使用qi::attr
:
qi::rule<It, Event()> slope = " - SLOPE: " >> attr(kind::SLOPE) >> double_;
qi::rule<It, Event()> gear = " - GEAR: " >> attr(kind::GEAR) >> double_;
有用的效果包括:您的编译时间可以缩减一半,并且属性值实际上也会传播(您的语义操作根本没有效果,并且主动抑制了自动属性传播......)。
有了这些改进,我们得到:
<强> Live On Coliru 强>
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/repository/include/qi_seek.hpp>
typedef std::string::const_iterator It;
enum kind { SLOPE, GEAR };
struct Event {
int event;
double value;
};
struct Location {
int driver;
double time;
double vel;
double km;
std::string date;
std::string road;
boost::optional<Event> event;
};
BOOST_FUSION_ADAPT_STRUCT(Event, event, value)
BOOST_FUSION_ADAPT_STRUCT(Location, date, time, driver, vel, road, km, event)
using ParsedData = std::vector<Location>;
namespace qi = boost::spirit::qi;
namespace px = boost::phoenix;
ParsedData parse_test(It b, It e) {
using namespace qi;
auto date = copy(
repeat(4)[digit] >> '-' >> repeat(3)[alpha] >> '-' >> repeat(2)[digit] >> ' ' >>
repeat(2)[digit] >> ':' >> repeat(2)[digit] >> ':' >> repeat(2)[digit] >> '.' >> +digit);
qi::rule<It, Event()> slope = " - SLOPE: " >> attr(kind::SLOPE) >> double_;
qi::rule<It, Event()> gear = " - GEAR: " >> attr(kind::GEAR) >> double_;
qi::rule<It, Location()> line = '[' >> raw[date] >> "] - "
>> double_ >> " s"
>> " => Driver: " >> int_
>> " - Speed: " >> double_
>> " - Road: " >> raw[+graph]
>> " - Km: " >> double_
>> -(slope | gear)
>> (eol | eoi);
ParsedData data;
parse(b, e, *boost::spirit::repository::qi::seek[line], data);
return data;
}
//Not all the lines will match the parser!
static std::string const input =
"[2018-Mar-13 13:13:59.580482] - 0.200 s => Driver: 0 - Speed: 0.0 - Road: A-11 - Km: 90.0 - SLOPE: 5.5\n\
[2018-Mar-13 13:14:01.170203] - 1.790 s => Driver: 0 - Speed: 0.0 - Road: A-11 - Km: 90.0 - GEAR: 1\n\
[2018-Mar-13 13:14:01.170203] - 1.790 s => Driver: 0 - Speed: 0.1 - Road: A-11 - Km: 90.0\n\
[2018-Mar-13 13:14:01.170203] - 1.790 s => I do not care about this line\n\
[2018-Mar-13 13:14:01.819966] - 2.440 s => Driver: 0 - Speed: 0.1 - Road: A-11 - Km: 90.0\n\
[2018-Mar-13 13:14:01.170203] - 2.440 s => Neither I do about this other line\n\
[2018-Mar-13 13:15:01.819966] - 3.440 s => Driver: 0 - Speed: 0.2 - Road: A-11 - Km: 90.0 - SLOPE: 10\n";
int main() {
auto parsed = parse_test(input.begin(), input.end());
std::cout << "Locations:\n";
for (Location const& loc : parsed) {
std::cout << "[" << loc.date << "] - " << loc.time << " s => Driver: " << loc.driver << " - Speed: " << loc.vel << " - Road: " << loc.road << " - Km: " << loc.km << std::endl;
if (loc.event)
std::cout << " - event: " << loc.event->event << " value: " << loc.event->value << "\n";
}
}
打印
Locations:
[2018-Mar-13 13:13:59.580482] - 0.2 s => Driver: 0 - Speed: 0 - Road: A-11 - Km: 90
- event: 0 value: 5.5
[2018-Mar-13 13:14:01.170203] - 1.79 s => Driver: 0 - Speed: 0 - Road: A-11 - Km: 90
- event: 1 value: 1
[2018-Mar-13 13:14:01.170203] - 1.79 s => Driver: 0 - Speed: 0.1 - Road: A-11 - Km: 90
[2018-Mar-13 13:14:01.1702032018-Mar-13 13:14:01.819966] - 2.44 s => Driver: 0 - Speed: 0.1 - Road: A-11 - Km: 90
[2018-Mar-13 13:14:01.1702032018-Mar-13 13:15:01.819966] - 3.44 s => Driver: 0 - Speed: 0.2 - Road: A-11 - Km: 90
- event: 0 value: 10