【问题标题】:How can I account for dates being entered in different formats?如何解释以不同格式输入的日期?
【发布时间】:2018-11-09 09:10:14
【问题描述】:

我有一个程序需要读取输入的日期。如果输入日期 D/MM/YYYY,我可以正确读取日期。当日期输入为 DD/MM/YYYY 时,它会错误地读取,因为 substr 没有考虑其中有 2 位数字的天数。

所以有 4 种不同的正确方式可以输入日期:

日/月/YYYY

DD/MM/YYYY

D/MM/YYYY

DD/M/YYYY

此外,如果输入了错误的日期/月份,例如 2018 年 4 月 100 日,则会妨碍正确读取字符串的其余部分。年份和月份。

通过我自己的测试,我有一个 for 循环来寻找第一个“/”,然后读取它之前的内容,但这没有用。

我该如何解释这些不同的日期输入方式?

MYDate::MYDate(std::string date) {

//int size = date.length();




SetYear(year_ = std::atoi(date.substr(5, 4).c_str()));
SetMonth(month_ = std::atoi(date.substr(3, 2).c_str()));
SetDay(day_ = std::atoi(date.substr(0, 2).c_str()));


/*
9/9/2001
09/09/2001
9/09/2001
09/9/2001
*/
}

【问题讨论】:

  • 你考虑过使用正则表达式吗?
  • 只要你尝试使用硬编码的字符串位置,这个问题就会一直存在。想象一下,您刚刚遇到一个从未见过约会对象的人,并试图向他们描述如何阅读约会对象;你当然不会告诉他们“位置 3 和 4 的字符代表月份”。
  • 看看std::string and it's find method。寻找 / 是正确的想法。它怎么不适合你?
  • @rafaelgonalez 我做了,但不知道从哪里开始。
  • @super 我实际上确实在 for 循环之前使用了 find 。我认为他们没有通过研究工作,因为 / 是一个转义字符。所以我尝试了 // & \/ 但没有任何乐趣。

标签: c++ date substr


【解决方案1】:

如果您替换“/”,您可以只使用 istringstream 进行一些简单的解析。像这样:

std::replace( date.begin(), date.end(), '/', ' ');

std::istringstream stream(date);

stream >> day_;
stream >> month_;
stream >> year_;

【讨论】:

  • 是的,这比我的回答要好,+1
【解决方案2】:

使用std::string::substr 拆分成令牌。这是一个简单的示例,足以让您入门:

#include <iostream>
#include <string>

int main () {
    std::string s = "09/09/2001";
    std::string delimiter = "/";

    size_t pos = 0;
    std::string token;
    int i = 0;
    while ((pos = s.find(delimiter)) != std::string::npos) {
        token = s.substr(0, pos);
        !i++ ? std::cout << "Day: " << token << std::endl : std::cout << "Month: " << token << std::endl;
        s.erase(0, pos + delimiter.length());
    }
    std::cout << "Year: " << s << std::endl;
    return 0;
}

输出:

Day: 09
Month: 09
Year: 2001

我检查了您要求的所有四个输入,并且它有效。

PS:你可能想要这些数字标记,所以请阅读How can I convert a std::string to int?

【讨论】:

    【解决方案3】:

    有多种方法可以从日期格式中提取\解析日期和时间,这就是我要做的:

    #include <tuple>
    #include <sstream>
    
    #define IS_LEAP_YEAR(year) ((year) % 4 == 0 && (year) % 100 != 0 || (year) % 100 == 0 && (year) % 400 == 0 || (year) % 400 == 0)
    
    std::tuple<int, int, int> GiveDateFromFormat(std::string const& format, char const delimiter = '\\')
    {
        std::stringstream ss(format);
        std::string date, month, year;
        std::getline(ss, date, delimiter);
        std::getline(ss, month, delimiter);
        std::getline(ss, year, delimiter);
        auto date_num = std::stoi(date), month_num = std::stoi(month), year_num = std::stoi(year);
        if (month_num > 12 || month_num < 1 || date_num >(month_num % 2 == 0 && month_num != 2 ? 30 : 31) ||
            date_num > (IS_LEAP_YEAR(year_num) ? 29 : 28) && month_num == 2)
            throw std::invalid_argument("Date does not exist!");
        return std::make_tuple(date_num, month_num, year_num);
    }
    

    请注意,日期检查只是为了确保,不是必需的...

    大大缩短,甚至可以:

    std::tuple<int, int, int> GiveDateFromFormat(std::string const& format, char const delimiter = '\\')
    {
        std::stringstream ss(format);
        std::string date, month, year;
        std::getline(ss, date, delimiter);
        std::getline(ss, month, delimiter);
        std::getline(ss, year, delimiter);
        return std::make_tuple(std::stoi(date), std::stoi(month), std::stoi(year));
    }
    

    用法:

    int main()
    {
        auto date_time = GiveDateFromFormat("29\\2\\2016");
        std::cout << "Date: " << std::get<0>(date_time) << std::endl
                  << "Month: " << std::get<1>(date_time) << std::endl
                  << "Year: " << std::get<2>(date_time) << std::endl;
        return 0;
    }
    

    输出:

    日期:29
    月:2
    年份:2016

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-04-02
      • 2014-06-02
      • 1970-01-01
      • 2015-10-01
      • 2015-12-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多