首先:我给了你all的那个在那个答案,在“具有特征的单独向量”下。唯一的区别似乎是类型和您所做的事实LogEvents
成员全局变量(ick)。
关于您的问题代码:
parse(b, e, *boost::spirit::repository::qi::seek[line], 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); }
};
请注意,容器不再是全球性的和他们有专有名称.
The boost::spirit::traits
专业相同(比照)除了我们现在有一个数据实例,所以我们绑定它(再次,如上面链接的原始示例,第 52 行,所以让我们修复用法:
ParsedData data;
parse(b, e, *boost::spirit::repository::qi::seek[line], data);
return data;
从这里开始,一切都奏效了。
进一步清理和演示
Notes:
- 没有理由在 C++ 中使用原始 char 数组和 strlen (我使用过
std::string
)
-
没有理由重复所有代码并命名所有内容_1
or _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方法完全按照我在链接答案中显示的方式(第 57/98 行)?如果你坚持“笨拙”地这样做,那就这样做not使用语义动作(Boost Spirit:“语义行为是邪恶的”?)但是使用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";
}
}
Printing
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