调用 lambda 的语义操作
Semantic actions calling lambda
我正在尝试使用 boost spirit 解析时间字符串,但不确定为什么这不起作用。
auto fill_ts_nanos = [&t] (int h, int m, int s, int ms) -> int
{ t.tv_nsec = ( ( h * 3600 + m * 60 + s ) * 1000 + ms ) * 1000000; return t.tv_sec; };
auto fill_suffix = [&suffix] (string &s) { suffix=s; };
auto parse_ok = qi::parse(input.begin(), input.end(),
( qi::int_ >> qi::char_(":") >> qi::int_ >> qi::char_(":") >>
qi::int_ >> qi::char_(".") >> qi::int_ )
[boost::bind(fill_ts_nanos, qi::_1, qi::_3, qi::_5, qi::_7
>> qi::char_(",") >> qi::as_string[*qi::char_][fill_suffix] ;
示例输入为“04:00:00.512,2251812698588658”
在猜测了很多细节之后(例如 t
的类型应该是什么),这里是带有一些调试输出的固定代码:
Note: I fixed the signed-ness of the numbers as well as I changed the types to prevent overflow.
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <ctime>
#include <chrono>
#include <iomanip>
namespace qi = boost::spirit::qi;
namespace px = boost::phoenix;
using namespace std::chrono_literals;
using namespace qi::labels;
int main() {
timespec t;
std::string suffix;
auto fill_ts_nanos = [&t](int h, unsigned m, unsigned s, unsigned ms) -> long {
t = {};
t.tv_nsec = ((h * 3600 + m * 60 + s) * 1000 + ms) * 1000000l;
return t.tv_sec;
};
auto fill_suffix = [&suffix](std::string &s) { suffix = s; };
std::string const input = "04:00:00.512,2251812698588658";
auto parse_ok = qi::parse(input.begin(), input.end(),
(qi::int_ >> ':' >> qi::uint_ >> ':' >> qi::uint_ >> '.' >> qi::uint_)
[px::bind(fill_ts_nanos, _1, _2, _3, _4) ]
>> ',' >> qi::as_string[*qi::char_]
[fill_suffix] );
std::printf("%lld.%.9ld\n", (long long)t.tv_sec, t.tv_nsec);
auto ns = t.tv_nsec * 1ns;
std::cout << std::fixed << std::setprecision(6);
std::cout << "hours: " << (ns / 1.0h) << "\n";
std::cout << "minutes: " << (ns / 1.0min) << "\n";
std::cout << "seconds: " << (ns / 1.0s) << "\n";
std::cout << "suffix: " << suffix << "\n";
return parse_ok? 0:255;
}
版画
0.14400512000000
hours: 4.000142
minutes: 240.008533
seconds: 14400.512000
suffix: 2251812698588658
建议
我会尽量简化它,例如,通过创建规则:
qi::rule<It, long()> timespec_ =
(qi::int_ >> ':' >> qi::uint_ >> ':' >> qi::uint_ >> '.' >> qi::uint_)
[ _val = ((_1 * 3600 + _2 * 60 + _3) * 1000 + _4) * 1000000l ];
这意味着您可以只解析:
timespec t {};
std::string suffix;
It f = input.begin(), l = input.end();
parse(f, l, timespec_ >> ',' >> *qi::char_, t.tv_nsec, suffix);
这具有相同的输出:
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <ctime>
#include <chrono>
#include <iomanip>
namespace qi = boost::spirit::qi;
namespace px = boost::phoenix;
using namespace std::chrono_literals;
using namespace qi::labels;
using It = std::string::const_iterator;
qi::rule<It, long()> timespec_ =
(qi::int_ >> ':' >> qi::uint_ >> ':' >> qi::uint_ >> '.' >> qi::uint_)
[ _val = ((_1 * 3600 + _2 * 60 + _3) * 1000 + _4) * 1000000l ];
int main() {
std::string const input = "04:00:00.512,2251812698588658";
timespec t {};
std::string suffix;
It f = input.begin(), l = input.end();
if (parse(f, l, timespec_ >> ',' >> *qi::char_, t.tv_nsec, suffix)) {
std::printf("%lld.%.9ld\n", (long long)t.tv_sec, t.tv_nsec);
auto ns = t.tv_nsec * 1ns;
std::cout << std::fixed << std::setprecision(6);
std::cout << "hours: " << (ns / 1.0h) << "\n";
std::cout << "minutes: " << (ns / 1.0min) << "\n";
std::cout << "seconds: " << (ns / 1.0s) << "\n";
std::cout << "suffix: " << suffix << "\n";
} else {
std::cout << "Parse failed\n";
}
if (f!=l) {
std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}
}
无奈之下,我也弄清楚了容器版本的工作原理。见下文,
auto test_fn = [&t](auto c) {
t.tv_nsec = ( ( at_c<0>(c) * 3600 +
at_c<2>(c) * 60 +
at_c<4>(c) ) * 1000 +
at_c<6>(c) ) * 1000000;
auto parse_ok = qi::parse(input.begin(), input.end(),
( qi::int_ >> qi::char_(":") >> qi::int_ >> qi::char_(":") >>
qi::int_ >> qi::char_(".") >> qi::int_ )[ test_fn ]
不可否认,它很丑。
我正在尝试使用 boost spirit 解析时间字符串,但不确定为什么这不起作用。
auto fill_ts_nanos = [&t] (int h, int m, int s, int ms) -> int
{ t.tv_nsec = ( ( h * 3600 + m * 60 + s ) * 1000 + ms ) * 1000000; return t.tv_sec; };
auto fill_suffix = [&suffix] (string &s) { suffix=s; };
auto parse_ok = qi::parse(input.begin(), input.end(),
( qi::int_ >> qi::char_(":") >> qi::int_ >> qi::char_(":") >>
qi::int_ >> qi::char_(".") >> qi::int_ )
[boost::bind(fill_ts_nanos, qi::_1, qi::_3, qi::_5, qi::_7
>> qi::char_(",") >> qi::as_string[*qi::char_][fill_suffix] ;
示例输入为“04:00:00.512,2251812698588658”
在猜测了很多细节之后(例如 t
的类型应该是什么),这里是带有一些调试输出的固定代码:
Note: I fixed the signed-ness of the numbers as well as I changed the types to prevent overflow.
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <ctime>
#include <chrono>
#include <iomanip>
namespace qi = boost::spirit::qi;
namespace px = boost::phoenix;
using namespace std::chrono_literals;
using namespace qi::labels;
int main() {
timespec t;
std::string suffix;
auto fill_ts_nanos = [&t](int h, unsigned m, unsigned s, unsigned ms) -> long {
t = {};
t.tv_nsec = ((h * 3600 + m * 60 + s) * 1000 + ms) * 1000000l;
return t.tv_sec;
};
auto fill_suffix = [&suffix](std::string &s) { suffix = s; };
std::string const input = "04:00:00.512,2251812698588658";
auto parse_ok = qi::parse(input.begin(), input.end(),
(qi::int_ >> ':' >> qi::uint_ >> ':' >> qi::uint_ >> '.' >> qi::uint_)
[px::bind(fill_ts_nanos, _1, _2, _3, _4) ]
>> ',' >> qi::as_string[*qi::char_]
[fill_suffix] );
std::printf("%lld.%.9ld\n", (long long)t.tv_sec, t.tv_nsec);
auto ns = t.tv_nsec * 1ns;
std::cout << std::fixed << std::setprecision(6);
std::cout << "hours: " << (ns / 1.0h) << "\n";
std::cout << "minutes: " << (ns / 1.0min) << "\n";
std::cout << "seconds: " << (ns / 1.0s) << "\n";
std::cout << "suffix: " << suffix << "\n";
return parse_ok? 0:255;
}
版画
0.14400512000000
hours: 4.000142
minutes: 240.008533
seconds: 14400.512000
suffix: 2251812698588658
建议
我会尽量简化它,例如,通过创建规则:
qi::rule<It, long()> timespec_ =
(qi::int_ >> ':' >> qi::uint_ >> ':' >> qi::uint_ >> '.' >> qi::uint_)
[ _val = ((_1 * 3600 + _2 * 60 + _3) * 1000 + _4) * 1000000l ];
这意味着您可以只解析:
timespec t {};
std::string suffix;
It f = input.begin(), l = input.end();
parse(f, l, timespec_ >> ',' >> *qi::char_, t.tv_nsec, suffix);
这具有相同的输出:
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <ctime>
#include <chrono>
#include <iomanip>
namespace qi = boost::spirit::qi;
namespace px = boost::phoenix;
using namespace std::chrono_literals;
using namespace qi::labels;
using It = std::string::const_iterator;
qi::rule<It, long()> timespec_ =
(qi::int_ >> ':' >> qi::uint_ >> ':' >> qi::uint_ >> '.' >> qi::uint_)
[ _val = ((_1 * 3600 + _2 * 60 + _3) * 1000 + _4) * 1000000l ];
int main() {
std::string const input = "04:00:00.512,2251812698588658";
timespec t {};
std::string suffix;
It f = input.begin(), l = input.end();
if (parse(f, l, timespec_ >> ',' >> *qi::char_, t.tv_nsec, suffix)) {
std::printf("%lld.%.9ld\n", (long long)t.tv_sec, t.tv_nsec);
auto ns = t.tv_nsec * 1ns;
std::cout << std::fixed << std::setprecision(6);
std::cout << "hours: " << (ns / 1.0h) << "\n";
std::cout << "minutes: " << (ns / 1.0min) << "\n";
std::cout << "seconds: " << (ns / 1.0s) << "\n";
std::cout << "suffix: " << suffix << "\n";
} else {
std::cout << "Parse failed\n";
}
if (f!=l) {
std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}
}
无奈之下,我也弄清楚了容器版本的工作原理。见下文,
auto test_fn = [&t](auto c) {
t.tv_nsec = ( ( at_c<0>(c) * 3600 +
at_c<2>(c) * 60 +
at_c<4>(c) ) * 1000 +
at_c<6>(c) ) * 1000000;
auto parse_ok = qi::parse(input.begin(), input.end(),
( qi::int_ >> qi::char_(":") >> qi::int_ >> qi::char_(":") >>
qi::int_ >> qi::char_(".") >> qi::int_ )[ test_fn ]
不可否认,它很丑。