Parse ISO 8601 durées
dans la norme ISO 8601, les durées sont données dans le format P[n]Y[n]M[n]DT[n]H[n]M[n]S
.
exemples:
20 secondes:
PT20.0S
un an, 2 mois, 3 jours, 4 heures, 5 minutes, 6 secondes:
P1Y2M3DT4H5M6S
Question:
donne une chaîne qui contient une durée au format iso 8601. Je veux obtenir le nombre total de secondes de ce durée. Quelle est la méthode recommandée dans la norme C++11 pour y parvenir?
remarques:
par exemple, il y a ptime from_iso_string(std::string) dans boost DateTime qui ne convient pas ici. Y a-t-il un moyen similaire sans faire un regex à la main?
2 réponses
utilisez la bibliothèque regex standard, le regex que vous voulez est quelque chose comme:
"P\(\([0-9]+\)Y\)?\(\([0-9]+\)M\)?\(\([0-9]+\)D\)?T\(\([0-9]+\)H\)?\(\([0-9]+\)M\)?\(\([0-9]+\(\.[0-9]+\)?S\)?"
à partir de cela, vous pouvez extraire le nombre d'années, mois etc et calculer le nombre total de secondes.
exemple de code pour la durée ISO 8601 au convertisseur de temps Unix epoch:
#include <iostream>
#include <vector>
#include <regex>
using namespace std;
void match_duration(const std::string& input, const std::regex& re)
{
std::smatch match;
std::regex_search(input, match, re);
if (match.empty()) {
std::cout << "Pattern do NOT match" << std::endl;
return;
}
std::vector<double> vec = {0,0,0,0,0,0}; // years, months, days, hours, minutes, seconds
for (size_t i = 1; i < match.size(); ++i) {
if (match[i].matched) {
std::string str = match[i];
str.pop_back(); // remove last character.
vec[i-1] = std::stod(str);
}
}
int duration = 31556926 * vec[0] + // years
2629743.83 * vec[1] + // months
86400 * vec[2] + // days
3600 * vec[3] + // hours
60 * vec[4] + // minutes
1 * vec[5]; // seconds
if (duration == 0) {
std::cout << "Not valid input" << std::endl;
return;
}
std::cout << "duration: " << duration << " [sec.]" << std::endl;
}
int main()
{
std::cout << "-- ISO 8601 duration to Unix epoch time converter--" << std::endl;
std::cout << "Enter duration (q for quit)" << std::endl;
std::string input;
//input = "P1Y2M3DT4H5M6S";
//input = "PT4H5M6S";
//
while(true)
{
std::cin >> input;
if (!std::cin)
break;
if (input == "q")
break;
std::regex rshort("^((?!T).)*$");
if (std::regex_match(input, rshort)) // no T (Time) exist
{
std::regex r("P([[:d:]]+Y)?([[:d:]]+M)?([[:d:]]+D)?");
match_duration(input, r);
}
else {
std::regex r("P([[:d:]]+Y)?([[:d:]]+M)?([[:d:]]+D)?T([[:d:]]+H)?([[:d:]]+M)?([[:d:]]+S|[[:d:]]+\.[[:d:]]+S)?");
match_duration(input, r);
}
}
return 0;
}