我将输入一个输入,如2021/10/7
(年/月/日)。我不会要求用户输入,我需要的代码能够正确读取输入。我不明白如何从Linux获得输入(日期),以及我的程序如何将该输入横向到我的代码中的适当位置。
我们已经简要地介绍了<fstream>
和ifstream inData; ofstream outData;
、.open
和.close
,但在我发布的样品溶液中的最后一次作业中,我使用了我完全不熟悉的freopen
。我特别向我的教授寻求帮助,但鼓励使用外部手段,如计算机科学和辅导,这些都没有多大帮助。
我正在寻找的是一种学习如何能够输入数据的方法,以便它可以从数据流中读取,以及我应该如何构建这样的东西,以便从Linux而不是用户获取输入。
编写程序从标准输入流中读取日期。
如果日期有效,程序应在工作日的英文名称(例如,"Monday", "Tuesday", "Wednesday",…,"Sunday"。函数main返回0
如果从标准输入流中读取的日期无效,程序应该写&;Error: invalid date&;。函数main返回1.
<<p>样本交互/strong>$ echo "2021/03/01" | ./pa04 0 Monday $ echo $? 0 $ echo " 2022/3/1" | ./pa04 1 Tuesday $ echo $? 0 $ echo "3/1/2022" | ./pa04 Error: invalid date $ echo $? 1 $ echo "abracadabra" | ./pa04 Error: invalid date $ echo $? 1
#include iostream
#include string
#include iomanip
#include cmath
using namespace std;
int main() {
int day, month, year, w;
// When I get here I feel there needs to be a cin.ignore() for the '/' in 2021/10/07.
// But I'm also concerned that if someone puts in 7 instead of 07 like in the sample interactions that it will jack up the results.
cin >> year >> month >> day;
w = (day + (13 * (month + 1) / 5) + (year) + (year / 4) - (year / 100) + (year / 400)) % 7;
switch (w) {
case 1:
cout << "Sunday n";
break;
case 2:
cout << "Monday n";
break;
case 3:
cout << "Tuesday n";
break;
case 4:
cout << "Wednesday n";
break;
case 5:
cout << "Thursday n";
break;
case 6:
cout << "Friday n";
break;
case 7:
cout << "Saturday n";
break;
}
return 0;
}
您根本没有处理/
字符。
你可以使用额外的>>
调用和变量:
int day, month, year;
char slash1, slash2;
if ((cin >> year >> slash1 >> month >> slash2 >> day) &&
(slash1 == '/') &&
(slash2 == '/'))
{
// use values as needed...
}
else
{
// invalid format...
}
或者,您可以使用istream::ignore()
跳过/
字符:
int day, month, year;
if (cin >> year &&
cin.ignore(numeric_limits<streamsize>::max(), '/') &&
cin >> month &&
cin.ignore(numeric_limits<streamsize>::max(), '/') &&
cin >> day)
{
// use values as needed...
}
else
{
// invalid format...
}
或者,在c++ 11及更高版本中,您可以使用std::get_time()
让标准库为您读入和解析日期组件:
#include <iomanip>
tm date;
if (cin >> get_time(&date, "%Y/%m/%d"))
{
int day = date.tm_mday;
int month = date.tm_mon + 1;
int year = date.tm_year + 1900;
int w = date.tm_wday + 1;
// use values as needed...
}
else
{
// invalid format...
}
使用std::get_time()
还有一个额外的好处,std::tm
有一个tm_wday
成员,用于一周中的一天,正如你上面看到的,所以你不必手动计算它。
您也可以使用c++ 20的std::chrono
。它允许你:
- 根据格式规范将输入字符串解析为时间对象(例如系统时钟中的天数)。
- 获取该时间对象的星期。
我发现std::chrono
的parse
方法:
-
不是很灵活。AFAIK,它不允许您使用正则表达式(例如,用于匹配输入字符串开头的空白,如在您的输入示例之一,
2022/4/2
;特别是,这可以很容易地修复在解析字符串之前修剪字符串)。 -
可能导致一些解析意外。例如,对于另一个输入示例
5/3/2023
,它将把日期解释为第5年的3月20日。也就是说,它会将日期匹配到输入字符串2023
中应该是日期的前两位数字20
。
所以我会选择混合溶液:
- 将输入字符串手工解析为时间对象。
- 然后使用
std::chrono
获取该时间对象对应的星期。
下面的代码在两个不同的函数using_just_chrono
和using_regex_and_chrono
中实现了这两个解决方案,只是为了显示我上面提到的问题,如果我们只使用std::chrono
。我使用正则表达式进行手动解析,但是您可以在做一些调整后使用字符串流捕获每个日期的年、月和日。
#include <chrono> // parse, sys_days, weekday
#include <iostream> // cout
#include <regex> // regex_match, smatch
#include <sstream> // istringstream
namespace ch = std::chrono;
void using_just_chrono(const std::string& date)
{
ch::year_month_day ymd{};
std::istringstream iss{ date };
if (iss >> ch::parse(std::string{ "%Y/%m/%d" }, ymd) and ymd.ok())
{
std::cout << "ttusing just chrono: " << ch::weekday{ ch::sys_days{ ymd } } << "n";
}
}
void using_regex_and_chrono(const std::string& date)
{
// Probably more portable using [[:space:]] and [[:digit:]] here
std::regex pattern{ R"(^s*(d{1,4})/(d{1,2})/(d{1,2})s*$)" };
std::smatch matches{};
if (std::regex_match(date, matches, pattern))
{
ch::year_month_day ymd(
ch::year{ std::stoi(matches[1]) },
ch::month{ std::stoul(matches[2]) },
ch::day{ std::stoul(matches[3]) });
if (ymd.ok())
{
std::cout << "ttusing rgx and chr: " << ch::weekday{ ch::sys_days{ ymd } } << "n";
}
}
}
int main()
{
std::cout << "Parsing dates:n";
for (const std::string& date : {
"2021/03/01", // OK
" 2022/4/2", // OK: needs trimming white spaces at the front
"5/3/2023", // wrong: day is 2023
"abracadabra", // wrong format
"2020/12/32", // wrong: day is 32
"2019/13/20", // wrong: month is 13
"2021/2/29" }) // wrong: non existing date
{
std::cout << "t"" << date << "":n";
using_just_chrono(date);
using_regex_and_chrono(date);
}
std::cout << "n";
}
// Outputs:
//
// Parsing dates:
// "2021/03/01":
// using just chrono: Mon
// using rgx and chr: Mon
// " 2022/4/2":
// using rgx and chr: Sat
// "5/3/2023":
// using just chrono: Sun
// "abracadabra":
// "2020/12/32":
// "2019/13/20":
// "2021/2/29":