Reputation: 589
Recently, our professor has requested that we use two char
variables (day) to receive the input from the user.
The code below works fine as a check to ensure that either Mo, Tu, We, Th, Fr, Sa, Su are the only two characters which are entered together as a pair. If anything else is received as input, it'll loop and ask the user for valid input.
The input should be case-insensitive, meaning that, for example, "mO"
and "tu"
are acceptable. It seems like there is a lot of repetition that is happening. Is there a way to clean this up?
cout << "Please enter the day of the week did you made the long distance call (Mo Tu We Th Fr Sa Su): ";
cin >> dayOne >> dayTwo;
while ((dayOne != 'M' && dayOne != 'm' || dayTwo != 'O' && dayTwo != 'o') &&
(dayOne != 'T' && dayOne != 't' || dayTwo != 'U' && dayTwo != 'u') &&
(dayOne != 'W' && dayOne != 'w' || dayTwo != 'e' && dayTwo != 'E') &&
(dayOne != 'T' && dayOne != 't' || dayOne != 'H' && dayTwo != 'h') &&
(dayOne != 'F' && dayOne != 'f' || dayTwo != 'R' && dayTwo != 'r') &&
(dayOne != 'S' && dayOne != 's' || dayTwo != 'A' && dayTwo != 'a') &&
(dayOne != 'S' && dayOne != 's' || dayTwo != 'U' && dayTwo != 'u'))
{
cin.clear();
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
cout << endl << "You have entered an invalid day. Please re-enter a day in the correct format (Mo Tu We Th Fr Sa Su): ";
cin >> dayOne >> dayTwo;
}
Upvotes: 41
Views: 2858
Reputation: 17955
I would first convert inputs to lowercase, which cuts on the amount of possible combinations. Then I would solve it with a single if-statement per day:
// returns 0-6 for valid days, -1 for invalid ones
int dayOfWeek(char a, char b) {
a = tolower(a); // requires #include <cctype>
b = tolower(b);
if (a == 'm' && b == 'o') return 0;
// 5 more here
if (a == 's' && b == 'u') return 6;
return -1; // date was invalid
}
And then I would use it as @PaulEvans suggested:
cout << "Please enter the day of the week did you made the long distance call (Mo Tu We Th Fr Sa Su): ";
cin >> dayOne >> dayTwo;
int day = -1;
while ((day = dayOfWeek(dayOne, dayTwo)) == -1)
{
cin.clear();
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
cout << endl << "You have entered an invalid day. Please re-enter a day in the correct format (Mo Tu We Th Fr Sa Su): ";
cin >> dayOne >> dayTwo;
}
// day is 0 for monday, ... 6 for sunday
Upvotes: 2
Reputation: 27577
Don't know if you're using/allowed regexes, but I'd solve it like this:
bool isDayOfTheWeek(char a, char b)
{
std::string day({a, b});
std::regex pattern("Mo|Tu|We|Th|Fr|Sa|Su", std::regex_constants::icase);
return std::regex_search(day, pattern);
}
Then simply:
cout << "Please enter the day of the week did you made the long distance call (Mo Tu We Th Fr Sa Su): ";
cin >> dayOne >> dayTwo;
while (!isDayOfTheWeek(dayOne, dayTwo))
{
cin.clear();
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
cout << endl << "You have entered an invalid day. Please re-enter a day in the correct format (Mo Tu We Th Fr Sa Su): ";
cin >> dayOne >> dayTwo;
}
Upvotes: 6
Reputation: 609
Another approach that might be worth mention is to organize your data, so that you can use std functions against it (std::find
)
// Example program
#include <algorithm>
#include <string>
#include <vector>
#include <iostream>
int main()
{
const std::vector<std::string> days = {
"mo", "tu", "we", "th", "fr", "sa", "su"
};
bool found = false;
while (found == false) {
char dayOne, dayTwo;
std::cout << "Please enter the first letter of the day" << std::endl;
std::cin >> dayOne;
std::cout << "Please enter the second letter of the day" << std::endl;
std::cin >> dayTwo;
std::string fullDay;
fullDay += std::tolower(dayOne);
fullDay += std::tolower(dayTwo);
found = std::find(days.begin(), days.end(), fullDay) != days.end();
std::cout << (found ? "correct day " : "invalid day, please try again ")
<< fullDay
<< std::endl;
}
}
run it here
Upvotes: 13
Reputation: 75
How about
switch (256 * tolower(dayOne) + tolower(dayTwo))
{
case 256 * 'm' + 'o':
// Monday
case 256 * 't' + 'u':
// Tuesday
}
and so on?
Upvotes: 8
Reputation: 60268
You could write a fold-expression that compares 2 characters to a string:
template<typename ...Days>
bool any_of(char a, char b, Days ...days)
{
return (... || (a == days[0] && b == days[1]));
}
and then use it like this:
while (! any_of(std::tolower(dayOne), std::tolower(dayTwo), "mo", "tu", "we", "th", "fr", "sa", "su"))
// keep asking for input
Here's a demo.
This should satisfy the requirement of using 2 char
inputs.
Upvotes: 41
Reputation: 28290
You typically use tolower
or toupper
to convert your char
variable to the correct case first. I like using tolower
- it looks marginally better.
dayOne = tolower(dayOne);
dayTwo = tolower(dayTwo);
while (
(dayOne != 'm' || dayTwo != 'o') &&
(dayOne != 't' || dayTwo != 'u') &&
(dayOne != 'w' || dayTwo != 'e') &&
(dayOne != 't' || dayTwo != 'h') &&
(dayOne != 'f' || dayTwo != 'r') &&
(dayOne != 's' || dayTwo != 'a') &&
(dayOne != 's' || dayTwo != 'u'))
{
...
}
You can further change it by using memcmp
to compare both characters at once, but I am not sure it would simplify the code.
Upvotes: 21