检查字符串在 C 中的格式是否正确

Check if string is in the correct format in C

我在函数中使用以下代码来检查字符串 '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;

谢谢!

我不相信你可以在 sscanf 中完成你所要求的。格式说明符指定最大宽度,但不指定最小宽度。因此,例如“%2d/%2d/%4d”将禁止使用“100/10/2014”,但不会禁止使用“1/10/2015”。

正如您在 post 中提到的,您可以计算数字。这将消除许多虚假的答案。如果你想要一个单一的语句并且不想进行边界检查(即检查以确保数据是有效的一天 - 所以月份不是 32 或类似的东西)你可以使用正则表达式。那将使用类似 std::regex_match (C++11 或更高版本)的东西。您可以在正确的正则表达式 here.

上找到更多信息

否则您将无法在解析后自行检查。

  • 编辑我对上面的内容不清楚。据我所知,C 没有标准的正则表达式库,但有几个可用的。当我从 C++ 指向 std::regex_match 时,更多的是给你一个你需要的常规库函数的例子。通常有可用的正则表达式库(如 posix 正则表达式),但它们往往不可移植。

正如评论中所建议的那样,使用正则表达式可能是你最好的选择,虽然你可以使用 if 条件,但那样会不那么简洁。

我不会用 C 编写代码,所以我不知道这是否完全正确,但是正则表达式应该类似于:

\d{2}\/\d{2}\/\d{4}

如果您不知道如何使用正则表达式,请参阅 this link for how to compile it。您可以在网上找到许多关于 C 正则表达式的教程以及更复杂的算法。

要使用 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;
}