我在函数中有以下代码来检查string' datestr'格式正确(dd / mm / yyyy):
if (sscanf(datestr, "%d/%d/%d", &day, &month, &year) != 3) return NULL;
虽然它适用于正确的格式化字符串,例如" 02/10 / 2015"它也适用于" 2/10 / 2015"格式不正确的日期和月份必须是2位数字长度和4位数字长度。 有没有办法可以在sscanf函数中检查这个? 或者我必须在使用if条件之前检查它?
if (!(strlen(datestr) == 10 && isdigit(datestr[0]) && isdigit(datestr[1]) && ...)) return NULL;
谢谢!
答案 0 :(得分:2)
要使用sscanf()
进行迂腐检查,请使用"%[]"
和"%n"
。
// if (sscanf(datestr, "%d/%d/%d", &day, &month, &year) != 3) return NULL;
int n[3] = { 0 };
sscanf(datestr, "%*[0-9]%n/%*[0-9]%n/%*[0-9]%n", &n[0], &n[1], &n[2]);
if (n[0] != 2 || n[1] != 5 || n[2] != 10) return NULL;
// Good To Go
sscanf(datestr, "%d/%d/%d", &day, &month, &year);
if (!ValidDate(year, month, day)) return NULL;
日期的各种测试,现代日期很容易。允许历史性日期很棘手。 Feb 30, 1712怎么样?
让代码使用计算机理解的日期
int ValidDate(int year, int month, int day) {
struct tm tm1 = { 0 };
tm1.tm_year = year - 1900;
tm1.tm_mon = month + 1;
tm1.tm_mday = day;
struct tm tm2 = tm1;
if (mktime(&tm1) == -1) return 0; // failed conversion.
// Did mktime() adjust fields?
if (tm1.tm_year != tm2.tm_year) return 0;
if (tm1.tm_mon != tm2.tm_mon) return 0;
return tm1.tm_mday == tm2.tm_mday;
}
答案 1 :(得分:0)
我不相信你可以在sscanf里面做你想要的。格式说明符指定最大宽度,但不指定最小宽度。因此,例如“%2d /%2d /%4d”将禁止“100/10/2014”,但不会禁止“2015年1月10日”。
正如您在帖子中提到的,您可以进行数字计数。这将消除许多虚假的答案。如果你想要一个单一的语句并且不想进行边界检查(即检查以确保数据是有效的一天 - 所以月份不是32或类似的那样)你可以使用正则表达式。那将使用类似std :: regex_match(C ++ 11或更高版本)的东西。您可以在正确的正则表达式here上找到更多信息。
否则你在解析后就会自行检查。
答案 2 :(得分:0)
正如评论中所建议的,使用正则表达式可能是您最好的选择,尽管您可以使用if
条件,但这样会更简洁。
我不用C编码,所以我不知道这是否完全正确,但是这个的正则表达式应该是这样的:
\d{2}\/\d{2}\/\d{4}
如果您不知道如何使用正则表达式,请参阅this link for how to compile it。您可以在Web上找到关于C regex的许多教程以及更复杂的算法。