わりとありそうな日付の表記ゆれをパースするグラマーを構築してみた。
#include <boost/spirit/include/qi.hpp> // boost::spirit::qi を利用します #include <boost/fusion/adapted/struct/adapt_struct.hpp> #include <iostream> #include <string> #include <boost/date_time.hpp> namespace pt = boost::posix_time; namespace qi = boost::spirit::qi; struct timeinfo { int16_t year_; uint16_t month_; uint16_t day_; uint16_t hour_; uint16_t minute_; uint16_t second_; //uint32_t millisec_; std::string millisec_; }; BOOST_FUSION_ADAPT_STRUCT( timeinfo, (int16_t, year_) (uint16_t, month_) (uint16_t, day_) (uint16_t, hour_) (uint16_t, minute_) (uint16_t, second_) //(uint32_t, millisec_) (std::string, millisec_) ) template <typename Iterator, typename Skipper> struct time_grammar : qi::grammar<Iterator, timeinfo(), Skipper> { qi::rule<Iterator, timeinfo(), Skipper> start_; qi::int_parser<int16_t,10,4,4> int4_; qi::uint_parser<uint16_t,10,2,2> uint2_; qi::rule<Iterator, std::string(), Skipper> numeric_; time_grammar() : time_grammar::base_type(start_, "time_grammar") { numeric_ = *qi::char_('0','9'); start_ = ( int4_ >> -(qi::lit('/') | qi::lit('-')) >> uint2_ >> -(qi::lit('/') | qi::lit('-')) >> uint2_ //>> (qi::lexeme[qi::lit(' ')] | qi::lit('T')) >> -(qi::lit('T')) >> uint2_ >> -(qi::lit(':')) >> uint2_ >> -(qi::lit(':')) >> uint2_ >> ( //-( (qi::lit('.') | qi::lit(',')) >> qi::uint_) -( (qi::lit('.') | qi::lit(',')) >> numeric_) | qi::attr(0) ) >> -(qi::lit('Z')) ); } }; int main() { std::string input[] = { "20210412T123455Z", "20210412T123455,987654321Z", "20210412T123455.987654321Z", "2004-03-21 12:45:33", "2004/03/21 12:45:33", "23.09.2004 04:12:21", "2003-02-11" }; time_grammar<std::string::iterator, qi::standard::space_type> myg; for( int i = 0; i < sizeof(input)/sizeof(input[0]); i++ ) { timeinfo ti; qi::phrase_parse( input[i].begin(), input[i].end(), myg, qi::standard::space, ti ); std::cout << "--------------" << std::endl; std::cout << ti.year_ << std::endl; std::cout << ti.month_ << std::endl; std::cout << ti.day_ << std::endl; std::cout << ti.hour_ << std::endl; std::cout << ti.minute_ << std::endl; std::cout << ti.second_ << std::endl; std::cout << ti.millisec_ << std::endl; } return 0; }2023/06/02 追記: lexeme がうまく動作しないのでスペースを無視した。millisec が ,020Z と指定された場合 2 に変換されてしまうので std::string で扱うようにした。バグでした。
0 件のコメント:
コメントを投稿