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

时间:2015-10-23 23:28:12

标签: c string formatting string-formatting

我在函数中有以下代码来检查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;

谢谢!

3 个答案:

答案 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上找到更多信息。

否则你在解析后就会自行检查。

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

答案 2 :(得分:0)

正如评论中所建议的,使用正则表达式可能是您最好的选择,尽管您可以使用if条件,但这样会更简洁。

我不用C编码,所以我不知道这是否完全正确,但是这个的正则表达式应该是这样的:

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

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