【问题标题】:Parse ISO 8601 durations解析 ISO 8601 持续时间
【发布时间】:2014-07-16 04:08:42
【问题描述】:

在 ISO 8601 中,持续时间以 P[n]Y[n]M[n]DT[n]H[n]M[n]S 的格式给出。

示例:

20 秒:

PT20.0S

一年2个月3天4小时5分6秒:

P1Y2M3DT4H5M6S

问题:

给定一个包含 iso 8601 格式的持续时间的字符串。我想获得该持续时间的总秒数。标准 C++11 中推荐的实现方式是什么?

备注:

例如,在 boost DateTime 中有 ptime from_iso_string(std::string) 不适合这里。有没有类似的方法不用手工做正则表达式?

【问题讨论】:

  • 如果您没有可用的正则表达式,为什么要专门要求“标准 C++11”?正则表达式是 C++11 标准的一部分 - 您更有可能寻找与 C++03 兼容的解决方案。
  • 你是对的,但我对两者都感兴趣:如何正确地做到这一点(使用 C++11)以及如何“暂时”做到这一点。我还认为,正则表达式解决方案是手动编码的。但既然它是一个标准,也许有一个现有的工具可以使用。

标签: c++ iso8601


【解决方案1】:

使用标准的正则表达式库,你想要的正则表达式是这样的:

"P\(\([0-9]+\)Y\)?\(\([0-9]+\)M\)?\(\([0-9]+\)D\)?T\(\([0-9]+\)H\)?\(\([0-9]+\)M\)?\(\([0-9]+\(\.[0-9]+\)?S\)?"

您可以从中提取年数、月数并计算总秒数。

【讨论】:

  • 谢谢你,不幸的是,我使用的是 gcc 4.8,标准正则表达式库还不能正常工作。更新到 gcc 4.9 会很困难,因为我的环境基于 QT,而最新版本的 gcc 4.8...
  • 然后使用Boost.RegexBoost.Xpressive 库。
  • 谢谢。但是,我想知道是否有一个标准解决方案,而无需手动编码正则表达式。这似乎是一个常见问题,例如boost DateTime 中有 ptime from_iso_string(std::string) 但这不适合。
【解决方案2】:

ISO 8601 持续时间到 Unix 纪元时间转换器的示例代码:

#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;
  }

【讨论】:

  • 你打算用edit 来完成这个想法吗?
  • @Drew 您的意思可能是“何时”而不是“地点”。现在我做到了。
猜你喜欢
  • 2014-08-16
  • 1970-01-01
  • 2010-11-11
  • 2021-02-16
  • 2021-05-21
  • 2021-12-12
  • 2021-10-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多