简体   繁体   English

C++ 月、日、年验证

[英]C++ Month, day, and year validation

I'm currently working on a project for my intro to C++ programming class.我目前正在为我的 C++ 编程课程介绍项目工作。 The project asks a user to enter a date using mm/dd/yyyy format.该项目要求用户使用 mm/dd/yyyy 格式输入日期。 Based on the information given, the program then has to determine if the date is valid or invalid, then displays a response to that.根据给出的信息,程序必须确定日期是有效还是无效,然后显示响应。 I'm facing the problem currently where everything is coming out reading "Good date!"我目前面临的问题是所有内容都在阅读“约会好!” I'm not sure where the problem is.我不确定问题出在哪里。 Any help is appreciated.任何帮助表示赞赏。 If you could help point me in the right direction, that would be awesome.如果你能帮助我指明正确的方向,那就太棒了。

#include <iostream>
#include <conio.h>

using namespace std;

void getDate(int *month, int *day, int *year);
int checkDate(int month, int day, int year);
void displayMessage(int status);

int main()
{
    int month, day, year;
    int s = 0;

    getDate(&month, &day, &year);
    do
    {
        checkDate(month, day, year);
        displayMessage(s);
        getDate(&month, &day, &year);
    } 
    while (_getch() != EOF);
}

void getDate(int *month, int *day, int *year)
{
    char fill;
    fill = '/';
    cout << "Enter a date in mm/dd/yyyy form: ";
    cin >> *month;
    if (cin.get() != '/')
    {
        cout << "expected /" << endl;
    }
    cin >> *day;
    if (cin.get() != '/')
    {
        cout << "expected /" << endl;
    }
    cin >> *year;
    cout << *month << fill << *day << fill << *year << endl;
};

int checkDate(int month, int day, int year)
{
    if ((month = 1) || (month = 3) || (month = 5) || (month = 7) ||
        (month = 8) || (month = 10) || (month = 12))
    {
        day <= 31;
    }
    else if ((month = 4) || (month = 6) || (month = 9) || (month = 11))
    {
        day <= 30;
    }
    else if ((month = 2) && (year % 4 == 0))
    {
    day <= 29;
    }
    else if ((month = 2) && (year % 4 != 0))
    {
        day <= 28;
    };
    int status = 0;
    if ((year < 999) || (year > 10000))
    {
        status == 1;
    }
    if ((month < 1) || (month > 12))
    {
        status == 2;
    }
    else if ((day < 1) || (day > 31))
    {
        status == 3;
    }
    else if ((day < 1) || (day > 30))
    {
        status == 4;
    }
    else if ((day < 1) || (day > 29))
    {
        status == 5;
    }
    else if ((day < 1) || (day > 28))
    {
        status == 6;
    }
    return status;
};

void displayMessage(int status)
{
    if (status == 0)
    {
        cout << "Good date!" << endl;
    }
    if (status == 1)
    {
        cout << "Bad year" << endl;
    }
    if (status == 2)
    {
        cout << "Bad month" << endl;
    }
    if (status == 3)
    {
        cout << "Bad day. Not 1-31" << endl;
    }
    if (status == 4)
    {
        cout << "Bad day, not 1-30" << endl;
    }
    if (status == 5)
    {
        cout << "Bad day, not 1-29" << endl;
    }
    if (status == 6)
    {
        cout << "Bad day, not 1-28" << endl;
    }
    _getch();
}

1) There are a couple of issues here, but the most obvious one is in main() : 1) 这里有几个问题,但最明显的是main()

int s=0; 
...
    checkDate(month, day, year);   // you don't store the status
    displayMessage(s);             // so s will always be 0 ! So good date !

You have to correct this:你必须纠正这个:

    s=checkDate(month, day, year); // store the result of the check        
    displayMessage(s);             // and take it to display the message  

2) Then in checkDate() , you mixup = and == . 2) 然后在checkDate() ,你混合=== = changes the value of the variable to its left. =将变量的值更改到其左侧。 == just makes a comparison but store nothing. ==只是进行比较,但不存储任何内容。 When correcting/adjusting, without any optimisation, your code should look like:更正/调整时,无需任何优化,您的代码应如下所示:

int checkDate(int month, int day, int year)
{
    int status=0; 

    if ((month == 1 || month == 3 || month == 5 || month == 7 ||
        month == 8 || month == 10 || month == 12) && ( day>31 || day<1) )
    {
        status = 3; 
    }
    else if ((month == 4 || month == 6 || month == 9 || month == 11) && (day>30 || day<1) )
    {
        status = 4; 
    }
    else if ((month == 2) && (year % 4 == 0) && (day>29 || day<1))
    {
        status = 5; 
    }
    else if ((month == 2) && (year % 4 != 0) && (day>28 || day<1) )
    {
        status = 6; 
    }
    else if ((year < 999) || (year > 10000))
    {
        status = 1;
    }
    if ((month < 1) || (month > 12))
    {
        status = 2;
    }
    return status;
};

3) After this, you should improve the input function, because: 3)在此之后,您应该改进输入功能,因为:

  • it doesn't cope with invalid separators.它不处理无效的分隔符。 If '/' are missing, an error message is displayed, but you continue the input as if everything was fine.如果缺少“/”,则会显示一条错误消息,但您可以继续输入,就好像一切正​​常一样。
  • it doesn't cope with invalid (ienon numeric) input.它不处理无效(ienon 数字)输入。 If user enters XI/1/2016 for example, your input will fail.例如,如果用户输入 XI/1/2016,您的输入将失败。

So keep in mind that (cin>>xxx) is an expression that you could use in an if and is true if everything was read correctly.所以请记住, (cin>>xxx)是一个可以在if使用的表达式,如果所有内容都被正确读取,则该表达式为真。 Also be aware that cin.clear() clears error flags that blocks input after a failure.还要注意cin.clear()清除在失败后阻止输入的错误标志。

A more compact and stripped checkDate (replace uppercase return by value)更紧凑和剥离的 checkDate (替换大写返回值)

int checkDate(int day, int month, int year) {
    if(day < 1 || day > 31) {
        return BADVALUE;
    } else if(month < 1 || month > 12) {
        return BADVALUE;
    } else if (year < MINYEAR || year > MAXYEAR) {
        return YEAROUTRANGE;
    }

    if ((month == 4 || month == 6 || month == 9 || month == 11) && day == 31) {
        return BADMONTHDAY; 
    } else if ((month == 2) && (year % 4 == 0) && day > 29) {
        return BADMONTHYEAR;

    } else if ((month == 2) && (year % 4 != 0) && day > 28) {
        return BADMONTHYEAR; 
    }
    return GOOD;
}

Can this also be achieved by a regular expression?这也可以通过正则表达式来实现吗?

I know there are many drawbacks in this approach, but still may be considered:我知道这种方法有很多缺点,但仍然可以考虑:

#include <regex>
#include <string>

using std::regex;
using std::regex_match;
using std::string;

// for ddmmyy
regex ddmmyy("^([0-2][0-9]|(3)[0-1])(((0)[0-9])|((1)[0-2]))\\d{2}$");

/* 
   for dd/mm/yy https://regex101.com/r/IqPLBJ/1
   for dd/mm/yyyy - could start from \\d{4}$ instead of \\d{2}$ bearing 0000-case in mind
*/
regex slashed_ddmmyy("^([0-2][0-9]|(3)[0-1])\/(((0)[0-9])|((1)[0-2]))\/\\d{2}$"); 

string f1 = "111223";
bool res = regex_match(f1,ddmmyy); // true

f1 = "112223";
res = regex_match(f1,ddmmyy); // false

res = regex_match(f1, slashed_ddmmyy); // false, no slashes

You also could make use of the function mktime() .您也可以使用函数mktime()

It tries to convert a given tm struct into a correct date.它尝试将给定的 tm 结构转换为正确的日期。 If the comparison of the individual members of the struct subsequently shows equality for all members, the given tm struct contained a valid date.如果结构的各个成员的比较随后显示所有成员都相等,则给定的 tm 结构包含有效日期。

bool CBorrow::validateDate(tm * timestruct)
{
    struct tm copy;
    copy.tm_sec = timestruct->tm_sec;
    copy.tm_min = timestruct->tm_min;
    copy.tm_hour = timestruct->tm_hour;
    copy.tm_mday = timestruct->tm_mday;
    copy.tm_mon = timestruct->tm_mon;
    copy.tm_year = timestruct->tm_year;
    copy.tm_wday = timestruct->tm_wday;
    copy.tm_yday = timestruct->tm_yday;
    copy.tm_isdst = timestruct->tm_isdst;

    time_t res = mktime(&copy);
    if (res < 0)
    {
        return false;
    }
    if (copy.tm_mday != timestruct->tm_mday
     || copy.tm_mon != timestruct->tm_mon
     || copy.tm_year != timestruct->tm_year)
    {
        return false;
    }
    return true;
}

Updated answer for C++20: C++20 的更新答案:

#include <chrono>
#include <iostream>

void
displayMessage(std::chrono::year_month_day ymd)
{
    using namespace std;
    using namespace std::chrono;
    if (!ymd.year().ok())
    {
        cout << "Bad year\n";
        return;
    }
    if (!ymd.month().ok())
    {
        cout << "Bad month\n";
        return;
    }
    if (!ymd.ok())
    {
        cout << "Bad day, not 1-" << (ymd.year()/ymd.month()/last).day() << '\n';
        return;
    }
    cout << "Good date!\n";
}

int
main()
{
    using namespace std::literals;
    displayMessage(29d/2/1900);
}

Output:输出:

Bad day, not 1-28

(1900 was not a leap year) (1900年不是闰年)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM