Schoolwork/자료구조와 C++프로그래밍

[C++] 2주차 과제2

FATKITTY 2020. 8. 5. 10:56
반응형

1주차에 작성한 학과명, 학번, 이름, 생년월일, 나이, 현재날짜를 출력하는 C++ 프로그램을 수정하여 다음 기능을 포함하도록 작성하라.

  • Exception handling을 구현하기 위한 try-catch의 구조를 이용하여 사용자의 입력 데이터에 오류가 있을 때 처리하는 프로그램을 작성하라. (사용자의 입력 오류로 프로그램이 오작동하는 경우가 발생하지 않도록 최대한 대처할 수 있도록 할 것)
  • 예: 생일 입력시  "2000/03/33"과 같이 잘못된 날짜를 입력한 경우 다시 입력할 것을 요구함

Code

// use class Date
// 이름, 학부(과)명에 숫자가 들어가지 않고, 학번에는 숫자만 들어간다고 가정했습니다.

#include <iostream>
#include <cstdlib>
#include <string>
#include <vector>
#include <ctime>
#pragma warning(disable:4996)
using namespace std;

const string currentDate()   // returns current date as string yyyy/mm/dd
{
    time_t current_time = time(NULL);  // save current time to now as type current_time
    struct tm timeinfo;
    char buf[80];
    timeinfo = *localtime(&current_time);
    strftime(buf, sizeof(buf), "%Y/%m/%d", &timeinfo);  // yyyy/mm/dd

    return buf;
}

class Date
{
public:
    void input(string whatday);  // '/'
    void output();  // 날짜출력형식
    void set(int newMonth, int newDay);  // year is not to be defined, month and day should form a possible date
    void check_match(int newMonth, int newDay);  // 예외처리 - if the month and the date doesn't match such as 4/31
    void check_lunar(int newYear, int newMonth, int newDay);  // 예외처리 - 2월 윤달인지 아닌지
    int getYear() { return year; }  // read the private member year
    int getMonth() { return month; }  // read month
    int getDay() { return day; }  // read day

private:
    int year;
    int month;
    int day;
};

class Information
{
public:
    string whole_info;
    void input();  // ','
    void output();
    int Age();
    string getBirthday() { return birthday; }

private:
    string department;
    string id_number;
    string name;
    string birthday;
    int age;
    string current_date;
};

void Date::set(int newMonth, int newDay)  // data conditions
{
    if (((newMonth < 1) || (newMonth > 12)) && ((newDay < 1) || (newDay > 31)))
        throw 3;

    if ((newMonth >= 1) && (newMonth <= 12))
        month = newMonth;
    else throw 1;

    if ((newDay >= 1) && (newDay <= 31))
        day = newDay;
    else throw 2;
}

void Date::check_match(int newMonth, int newDay)   // does the month and date match each other?
{
    // 1/31, 2/28, 3/31, 4/30, 5/31, 6/30, 7/30, 8/31, 9/30, 10/31, 11/30, 12/31 - 4,6,7,9,11
    if ((newMonth == 4) && (newDay > 30) && (newDay <= 31) || (newMonth == 6) && (newDay > 30) && (newDay <= 31) || (newMonth == 7) && (newDay > 30) && (newDay <= 31)
        || (newMonth == 9) && (newDay > 30) && (newDay <= 31) || (newMonth == 11) && (newDay > 30) && (newDay <= 31))
        throw 4;
}

void Date::check_lunar(int newYear, int newMonth, int newDay)  // 윤년에 대한 예외처리
{
    if ((newYear % 4 == 0) && (newYear % 100 != 0) || (newYear % 400 == 0)) {
        if ((newMonth == 2) && (newDay > 29) && (newDay <= 31))
            throw 5;
    }
    else {
        if ((newMonth == 2) && (newDay > 28) && (newDay <= 31))
            throw 6;
    }
}

void Date::input(string whatday)  // parse string into year, month and day
{
    // slash 기준으로 string parsing 후 int로 형변환하고 각각 맞는 private 변수에 저장
    int count_slash = 0;
    string delimiter = "/";
    size_t last = 0;
    size_t next = 0;
    string token;
    vector<string> date_token;
    while ((next = whatday.find(delimiter, last)) != string::npos)
    {
        token = whatday.substr(last, next - last);
        date_token.push_back(token);
        last = next + 1;
        count_slash++;
    }
    date_token.push_back(whatday.substr(last));

    // slash 2개 아니면 다시 입력
    if (count_slash != 2) throw 13;

    // 예외처리 - 입력값에 숫자 아닌게 섞였는지 판별
    for (int i = 0; i < 3; i++)
    {
        for (int idx = 0; idx < (date_token[i].length()); idx++) {
            if ((date_token[i][idx] <= 57) && (date_token[i][idx] >= 48)) {}
            else throw 13;
        }
    }

    year = stoi(date_token[0]);
    month = stoi(date_token[1]);
    day = stoi(date_token[2]);
    set(month, day);  // month, day 가 유효한 값인지 확인
    check_match(month, day);  // 입력한 날짜가 진짜 정상적인지 확인
    check_lunar(year, month, day);  // 윤년인지 아닌지 확인
}

void Date::output()  // ~년~월~일
{
    cout << year << "년" << month << "월" << day << "일";
}

void Information::input()  // 예외처리 - 4가지 중 하나라도 입력 안 했을 때. 아무것도 입력 안 했을 때
{
    cout << "환영합니다! 학과명, 학번, 이름, 생년월일(yyyy/mm/dd)을 입력하세요> ";

    department.clear();
    id_number.clear();
    name.clear();
    birthday.clear();
    whole_info.clear();  // 초기화

    // 쉼표+공백 때문에 while 돌려서 전체 입력값 저장
    getline(cin, whole_info);
    if (whole_info.length() == 0) throw 14;  // 입력값이 아무것도 없으면 throw
    
    int count_comma = 0;
    for (int check_comma = 0; check_comma < whole_info.length(); check_comma++)
    {
        if (whole_info[check_comma] == ',') { count_comma++; }
    }
    // 쉼표 3개 아니면 다시 입력
    if (count_comma != 3) throw 8;

    count_comma = 0;
    for (int check_parse = 0; check_parse < whole_info.length(); check_parse++)
    {
        if (whole_info[check_parse] == ',') { count_comma++; }
        if (whole_info[check_parse] == ' ') {}
        if ((whole_info[check_parse] != ',') && (whole_info[check_parse] != ' ')) {
            if (count_comma == 0) department += whole_info[check_parse];
            if (count_comma == 1) id_number += whole_info[check_parse];
            if (count_comma == 2) name += whole_info[check_parse];
            if (count_comma == 3) birthday += whole_info[check_parse];
        }
    }

    // 쉼표는 3개지만 입력값이 비었을 때
    if (department.length() == 0) throw 9;
    if (id_number.length() == 0) throw 10;
    if (name.length() == 0) throw 11;
    if (birthday.length() == 0) throw 12;

    // 예외처리 - 학부(과)명 입력할 곳에 숫자가 있을 때
    for (int idx = 0; idx < (department.length()); idx++) {
        if ((department[idx] <= 57) && (department[idx] >= 48)) throw 8; // ascii
    }

    // 예외처리 - 이름 입력할 곳에 숫자가 있을 때
    for (int idx = 0; idx < (name.length()); idx++) {
        if ((name[idx] <= 57) && (name[idx] >= 48)) throw 8;
    }

    // 예외처리 - 학번 입력할 곳에 숫자가 없을 때
    for (int idx = 0; idx < (id_number.length()); idx++) {
        if ((id_number[idx] <= 57) && (id_number[idx] >= 48)) {}
        else throw 8;
    }

    // 예외처리 - 생일 입력할 곳에 숫자,/ 외 다른 것이 입력됐을 때, /의 위치가 이상할 때
    for (int idx = 0; idx < (birthday.length()); idx++) {
        if ((birthday[idx] <= 57) && (birthday[idx] >= 47)) {}  // numbers and slash
        else throw 13;
    }

    Date date;
    date.input(birthday);
}

int Information::Age()  // 만 나이 = 생일 지났으면 (현재년도-출생년도), 생일 안 지났으면 (현재년도-출생년도-1)
{
    Date date;
    string currentdate = currentDate();
    date.input(currentdate);
    int currentyear = date.getYear();
    int currentmonth = date.getMonth();
    int currentday = date.getDay();
    date.input(birthday);
    int birthyear = date.getYear();
    int birthmonth = date.getMonth();
    int birthday = date.getDay();

    // 현재 날짜가 생월을 지난 경우
    if (currentmonth > birthmonth) age = currentyear - birthyear;
    // 현재 날짜가 생월인 경우 : 생일이거나 지남 or 생일 전
    if (currentmonth == birthmonth && currentday >= birthday) age = currentyear - birthyear;
    if (currentmonth == birthmonth && currentday < birthday) age = currentyear - birthyear - 1;
    // 현재 날짜가 생월 이전인 경우
    if (currentmonth < birthmonth) age = currentyear - birthyear - 1;

    // 예외처리 - 현재 날짜보다 생일 날짜가 뒤에 있는 경우
    if ((currentyear < birthyear) || (currentyear == birthyear) && (currentmonth < birthmonth) || (currentyear == birthyear) && (currentmonth == birthmonth) && (currentday < birthday))
        throw 7;

    return age;
}

void Information::output()  // department, id_number, name, birthday, age, current_date
{
    Date date;
    date.input(birthday);
    Age();

    cout << ">> " << department << " " << id_number << " " << name << "님 ";
    date.output();
    cout << "생 ";

    date.input(currentDate());
    date.output();
    cout << " 현재 " << age << "세입니다." << endl;
}

int main()
{
    Information info;
    while (1)
    {
        try {
            info.input();
        }
        catch (int i) {
            cout << "\n";
            if (i == 1) { cout << "생월 입력값이 잘못되었습니다." << endl; }
            if (i == 2) { cout << "생일 입력값이 잘못되었습니다." << endl; }
            if (i == 3) { cout << "생월, 생일 입력값이 모두 잘못되었습니다." << endl; }
            if (i == 4) { cout << "해당 생월에 존재하지 않는 날짜입니다." << endl; }
            if (i == 5) { cout << "윤년에 존재하지 않는 날짜입니다." << endl; }
            if (i == 6) { cout << "존재하지 않는 날짜입니다." << endl; }
            if (i == 8) { cout << "입력값 4가지를 모두 순서, 조건에 맞게 입력했는지 확인해주세요." << endl; }
            if (i == 9) { cout << "학부(과)명을 입력했는지 확인해주세요." << endl; }
            if (i == 10) { cout << "학번을 입력했는지 확인해주세요." << endl; }
            if (i == 11) { cout << "이름을 입력했는지 확인해주세요." << endl; }
            if (i == 12) { cout << "생년월일을 입력했는지 확인해주세요." << endl; }
            if (i == 13) { cout << "생년월일을 정확히 입력했는지 확인해주세요." << endl; }
            if (i == 14) { cout << "입력값이 없습니다." << endl; }
            cout << "이름, 학부(과)명에는 숫자를 입력할 수 없고, 학번에는 숫자만 입력 가능합니다.\n확인 후 다시 입력해주세요.\n" << endl;
            i = 0;
            continue;
        }
        try {
            info.output();
        }
        catch (int j) {
            if (j == 7) { cout << "유효하지 않은 생년월일입니다." << endl; }
            cout << "확인 후 다시 입력해주세요.\n" << endl;
            j = 0;
            continue;
        }
        break;
    }
}

실행결과

 

점수 10/10

 

 

  ❤와 댓글은 큰 힘이 됩니다. 감사합니다 :-)  

반응형

'Schoolwork > 자료구조와 C++프로그래밍' 카테고리의 다른 글

[C++] 9주차 과제6  (0) 2020.08.05
[C++] 7주차 과제5  (0) 2020.08.05
[C++] 5주차 과제4  (0) 2020.08.05
[C++] 3주차 과제3  (0) 2020.08.05
[C++] 1주차 과제1  (0) 2020.08.05