如何在 C++ 中解析和验证 std::string 中的日期
How to parse and validate a date in std::string in C++?
我正在做一个项目,我必须读取一个日期以确保它是一个有效的日期。例如,2 月 29 日只是闰年的有效日期,或者 6 月 31 日不是有效日期,因此计算机将根据输入输出该信息。我的问题是我无法弄清楚如何解析字符串,以便用户可以输入"05/11/1996"作为日期(例如),然后将其放入单独的整数中。我正在考虑尝试用 while 循环和字符串流做一些事情,但我有点卡住了。如果有人能帮助我解决这个问题,我将不胜感激。
一个可能的解决方案也可能基于 strptime
,但请注意,此函数仅验证一天是否来自 <1;12>
的区间<1;31>
和月,即 "30/02/2013"
仍然有效:
#include <iostream>
#include <ctime>
int main() {
struct tm tm;
std::string s("32/02/2013");
if (strptime(s.c_str(), "%d/%m/%Y", &tm))
std::cout << "date is valid" << std::endl;
else
std::cout << "date is invalid" << std::endl;
}
但是,由于strptime
并不总是可用,并且额外的验证会很好,因此您可以执行以下操作:- 提取日、月、年
- 填充
struct tm
- 规范化它
- 检查规范化日期是否仍与检索到的日、月、年相同
即:
#include <iostream>
#include <sstream>
#include <ctime>
// function expects the string in format dd/mm/yyyy:
bool extractDate(const std::string& s, int& d, int& m, int& y){
std::istringstream is(s);
char delimiter;
if (is >> d >> delimiter >> m >> delimiter >> y) {
struct tm t = {0};
t.tm_mday = d;
t.tm_mon = m - 1;
t.tm_year = y - 1900;
t.tm_isdst = -1;
// normalize:
time_t when = mktime(&t);
const struct tm *norm = localtime(&when);
// the actual date would be:
// m = norm->tm_mon + 1;
// d = norm->tm_mday;
// y = norm->tm_year;
// e.g. 29/02/2013 would become 01/03/2013
// validate (is the normalized date still the same?):
return (norm->tm_mday == d &&
norm->tm_mon == m - 1 &&
norm->tm_year == y - 1900);
}
return false;
}
用作:
int main() {
std::string s("29/02/2013");
int d,m,y;
if (extractDate(s, d, m, y))
std::cout << "date "
<< d << "/" << m << "/" << y
<< " is valid" << std::endl;
else
std::cout << "date is invalid" << std::endl;
}
在这种情况下,这将输出date is invalid
,因为规范化会检测到29/02/2013
已规范化为 01/03/2013
.
另一种选择是使用 <iomanip>
标头中的std::get_time
(自 C++11 起可用)。可以在此处找到其使用的一个很好的例子。
我更喜欢使用Boost DateTime:
在科里鲁现场观看
#include <iostream>
#include <boost/date_time/local_time/local_time.hpp>
struct dateparser
{
dateparser(std::string fmt)
{
// set format
using namespace boost::local_time;
local_time_input_facet* input_facet = new local_time_input_facet();
input_facet->format(fmt.c_str());
ss.imbue(std::locale(ss.getloc(), input_facet));
}
bool operator()(std::string const& text)
{
ss.clear();
ss.str(text);
bool ok = ss >> pt;
if (ok)
{
auto tm = to_tm(pt);
year = tm.tm_year;
month = tm.tm_mon + 1; // for 1-based (1:jan, .. 12:dec)
day = tm.tm_mday;
}
return ok;
}
boost::posix_time::ptime pt;
unsigned year, month, day;
private:
std::stringstream ss;
};
int main(){
dateparser parser("%d/%m/%Y"); // not thread safe
// parse
for (auto&& txt : { "05/11/1996", "30/02/1983", "29/02/2000", "29/02/2001" })
{
if (parser(txt))
std::cout << txt << " -> " << parser.pt << " is the "
<< parser.day << "th of "
<< std::setw(2) << std::setfill('0') << parser.month
<< " in the year " << parser.year << "n";
else
std::cout << txt << " is not a valid daten";
}
}
输出:
05/11/1996 -> 1996-Nov-05 00:00:00 is the 5th of 11 in the year 96
30/02/1983 is not a valid date
29/02/2000 -> 2000-Feb-29 00:00:00 is the 29th of 02 in the year 100
29/02/2001 is not a valid date
如果格式类似于您的示例,您可以像这样取出整数:
int day, month, year;
sscanf(buffer, "%2d/%2d/%4d",
&month,
&day,
&year);
当然,在缓冲区中你有日期("05/11/1996")
相关文章:
- cppcheck在const std::string[]上引发警告
- 将std::string传递给WriteConsole API
- 为std::string的某个索引赋值
- 使用 std::string () const 函数启动线程或未来
- 当我们进行一些操作时,应该使用什么'std::string'或'std::stringstream'?
- 如何更改大小(std::string)
- std::string 的对象真的可以移动吗?
- SegFault 同时使用 std::string::operator+= 和函数作为参数
- 无法从 std::string 中提取C++ Unicode 符号
- std::string 构造函数如何处理固定大小的 char[]?
- 真的没有来自 std::string_view 的 std::string 的显式构造函数吗?
- 将C++ std::string 转换为 UTF-16-LE 编码的字符串
- 重载 + 自己的类和 std::string 的运算符
- 如何使用 std::string 作为 QHash 的键?
- 将日语 wstring 转换为 std::string
- 可以从std::string继承以提供类型一致性吗
- 构造函数采用std::string_view与std::string并移动
- 在共享缓冲区内存中创建 ::std::string 对象
- std::string.size() 未知行为
- Valgrind 在 std::string::swap 中报告 SIGILL