implement ISO 8601 durations parsing, cf. #1399
This commit is contained in:
parent
73a2a938b4
commit
7e00a86bb4
@ -29,6 +29,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#define EXTRACTION_HELPER_FUNCTIONS_HPP
|
||||
|
||||
#include "../util/cast.hpp"
|
||||
#include "../util/iso_8601_duration_parser.hpp"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/algorithm/string_regex.hpp>
|
||||
@ -37,24 +38,43 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace qi = boost::spirit::qi;
|
||||
|
||||
// TODO: Move into LUA
|
||||
|
||||
bool durationIsValid(const std::string &s)
|
||||
bool simple_duration_is_valid(const std::string &s)
|
||||
{
|
||||
boost::regex e(
|
||||
boost::regex simple_format(
|
||||
"((\\d|\\d\\d):(\\d|\\d\\d):(\\d|\\d\\d))|((\\d|\\d\\d):(\\d|\\d\\d))|(\\d|\\d\\d)",
|
||||
boost::regex_constants::icase | boost::regex_constants::perl);
|
||||
|
||||
std::vector<std::string> result;
|
||||
boost::algorithm::split_regex(result, s, boost::regex(":"));
|
||||
const bool matched = regex_match(s, e);
|
||||
return matched;
|
||||
const bool simple_matched = regex_match(s, simple_format);
|
||||
|
||||
if (simple_matched)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool iso_8601_duration_is_valid(const std::string &s)
|
||||
{
|
||||
iso_8601_grammar<std::string::const_iterator> iso_parser;
|
||||
const bool result = qi::parse(s.begin(), s.end(), iso_parser);
|
||||
|
||||
// check if the was an error with the request
|
||||
if (result && (0 != iso_parser.get_duration()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool durationIsValid(const std::string &s)
|
||||
{
|
||||
return simple_duration_is_valid(s) || iso_8601_duration_is_valid(s);
|
||||
}
|
||||
|
||||
unsigned parseDuration(const std::string &s)
|
||||
{
|
||||
if (simple_duration_is_valid(s))
|
||||
{
|
||||
unsigned hours = 0;
|
||||
unsigned minutes = 0;
|
||||
unsigned seconds = 0;
|
||||
@ -84,6 +104,15 @@ unsigned parseDuration(const std::string &s)
|
||||
}
|
||||
return 10 * (3600 * hours + 60 * minutes + seconds);
|
||||
}
|
||||
}
|
||||
else if (iso_8601_duration_is_valid(s))
|
||||
{
|
||||
iso_8601_grammar<std::string::const_iterator> iso_parser;
|
||||
qi::parse(s.begin(), s.end(), iso_parser);
|
||||
|
||||
return iso_parser.get_duration();
|
||||
}
|
||||
|
||||
return std::numeric_limits<unsigned>::max();
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@ Feature: Car - Handle ferry routes
|
||||
| c | f | cde,efg | 2,1 |
|
||||
| c | g | cde,efg | 2,1 |
|
||||
|
||||
Scenario: Car - Properly handle durations
|
||||
Scenario: Car - Properly handle simple durations
|
||||
Given the node map
|
||||
| a | b | c | | |
|
||||
| | | d | | |
|
||||
@ -45,3 +45,22 @@ Feature: Car - Handle ferry routes
|
||||
| b | f | abc,cde,efg | 1,2,1 | 20 km/h |
|
||||
| c | e | cde | 2 | 12 km/h |
|
||||
| e | c | cde | 2 | 12 km/h |
|
||||
|
||||
Scenario: Car - Properly handle ISO 8601 durations
|
||||
Given the node map
|
||||
| a | b | c | | |
|
||||
| | | d | | |
|
||||
| | | e | f | g |
|
||||
|
||||
And the ways
|
||||
| nodes | highway | route | duration |
|
||||
| abc | primary | | |
|
||||
| cde | | ferry | PT1M |
|
||||
| efg | primary | | |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | modes | speed |
|
||||
| a | g | abc,cde,efg | 1,2,1 | 26 km/h |
|
||||
| b | f | abc,cde,efg | 1,2,1 | 20 km/h |
|
||||
| c | e | cde | 2 | 12 km/h |
|
||||
| e | c | cde | 2 | 12 km/h |
|
||||
|
64
unit_tests/algorithms/duration_parsing.cpp
Normal file
64
unit_tests/algorithms/duration_parsing.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "../../extractor/extraction_helper_functions.hpp"
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/test/test_case_template.hpp>
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(durations_are_valid)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(all_necessary_test)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(durationIsValid("00:01"), true);
|
||||
BOOST_CHECK_EQUAL(durationIsValid("00:01:01"), true);
|
||||
BOOST_CHECK_EQUAL(durationIsValid("PT15M"), true);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(common_durations_get_translated)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(parseDuration("00:01"), 600);
|
||||
BOOST_CHECK_EQUAL(parseDuration("00:01:01"), 610);
|
||||
BOOST_CHECK_EQUAL(parseDuration("01:01"), 36600);
|
||||
|
||||
// check all combinations of iso duration tokens
|
||||
BOOST_CHECK_EQUAL(parseDuration("PT1M1S"), 610);
|
||||
BOOST_CHECK_EQUAL(parseDuration("PT1H1S"), 36010);
|
||||
BOOST_CHECK_EQUAL(parseDuration("PT15M"), 9000);
|
||||
BOOST_CHECK_EQUAL(parseDuration("PT15S"), 150);
|
||||
BOOST_CHECK_EQUAL(parseDuration("PT15H"), 540000);
|
||||
BOOST_CHECK_EQUAL(parseDuration("PT1H15M"), 45000);
|
||||
BOOST_CHECK_EQUAL(parseDuration("PT1H15M1S"), 45010);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(iso_8601_durations_case_insensitive)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(parseDuration("PT15m"), 9000);
|
||||
BOOST_CHECK_EQUAL(parseDuration("PT1h15m"), 45000);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
102
util/iso_8601_duration_parser.hpp
Normal file
102
util/iso_8601_duration_parser.hpp
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef ISO_8601_DURATION_PARSER_HPP
|
||||
#define ISO_8601_DURATION_PARSER_HPP
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/spirit/include/qi.hpp>
|
||||
#include <boost/spirit/include/qi_action.hpp>
|
||||
|
||||
namespace qi = boost::spirit::qi;
|
||||
|
||||
template <typename Iterator> struct iso_8601_grammar : qi::grammar<Iterator>
|
||||
{
|
||||
iso_8601_grammar()
|
||||
: iso_8601_grammar::base_type(iso_period), temp(0), hours(0), minutes(0), seconds(0)
|
||||
{
|
||||
iso_period = qi::lit('P') >> qi::lit('T') >>
|
||||
((value >> hour >> value >> minute >> value >> second) |
|
||||
(value >> hour >> value >> minute) | (value >> hour >> value >> second) |
|
||||
(value >> hour) | (value >> minute >> value >> second) | (value >> minute) |
|
||||
(value >> second));
|
||||
|
||||
value = qi::uint_[boost::bind(&iso_8601_grammar<Iterator>::set_temp, this, ::_1)];
|
||||
second = (qi::lit('s') |
|
||||
qi::lit('S'))[boost::bind(&iso_8601_grammar<Iterator>::set_seconds, this)];
|
||||
minute = (qi::lit('m') |
|
||||
qi::lit('M'))[boost::bind(&iso_8601_grammar<Iterator>::set_minutes, this)];
|
||||
hour = (qi::lit('h') |
|
||||
qi::lit('H'))[boost::bind(&iso_8601_grammar<Iterator>::set_hours, this)];
|
||||
}
|
||||
|
||||
qi::rule<Iterator> iso_period;
|
||||
qi::rule<Iterator, std::string()> value, hour, minute, second;
|
||||
|
||||
unsigned temp;
|
||||
unsigned hours;
|
||||
unsigned minutes;
|
||||
unsigned seconds;
|
||||
|
||||
void set_temp(unsigned number) { temp = number; }
|
||||
|
||||
void set_hours()
|
||||
{
|
||||
if (temp < 24)
|
||||
{
|
||||
hours = temp;
|
||||
}
|
||||
}
|
||||
|
||||
void set_minutes()
|
||||
{
|
||||
if (temp < 60)
|
||||
{
|
||||
minutes = temp;
|
||||
}
|
||||
}
|
||||
|
||||
void set_seconds()
|
||||
{
|
||||
if (temp < 60)
|
||||
{
|
||||
seconds = temp;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned get_duration() const
|
||||
{
|
||||
unsigned temp = 10 * (3600 * hours + 60 * minutes + seconds);
|
||||
if (temp == 0)
|
||||
{
|
||||
temp = std::numeric_limits<unsigned>::max();
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // ISO_8601_DURATION_PARSER_HPP
|
Loading…
Reference in New Issue
Block a user