C语言 验证重定向为输入的文件中的日期



首先,这是一个家庭作业问题。

具有 mm/dd/yyyy 格式的日期列表的文件将从命令提示符重定向为输入。下面是一个 ./main.out


我的教授给出了一个关于什么构成无效日期的标准。

1.) 如果有任何非数字字符,例如 12/4A/199A5。

2.) 如果他们缺少正斜杠或正斜杠超过 2 个。

3.) 如果它们是浮点数,例如 12/4/1995.3

4.) 如果它们是不正确的日期,例如 2/29/1973,因为 29 意味着该年应该是闰年,但 1973 年不能被 4 或 400 整除。

5.) 如果没有日期(空字符串)或缺少部分日期,例如 4/3/。


以下是有效日期的示例。

1.) 带有前导或尾随空格的日期,如 12/23/1694

2.) 带有前导零的日期,如 004/030/2000

3.) 任何月份数在 1 到 12 之间的日期,正确的日长(这取决于月份)和年份可以是正数、负数或零。


以下是我到目前为止所做的,仅使用必要的相关功能。

int writeToFile()
{
    FILE *outputFile;
    char buffer[BUFFERSIZE];
    int month = 0, days = 0, year = 0;
    int isValidFormat = 0, isValidDate = 0;
    size_t strDateLength;
    outputFile = fopen("Output.dat", "w");
    if(outputFile == NULL)
    {
        fprintf(stderr, "Couldn't write to the file.n");
        return FALSE;
    }
    while(fgets(buffer, BUFFERSIZE, stdin))
    {
        strDateLength = strlen(buffer);
        if(buffer[strDateLength - 1] != 'n' && strDateLength <  BUFFERSIZE - 1)
        {
            appendNewLine(buffer, strDateLength);
        }
        isValidFormat = validateDateFormat(buffer, &month, &days, &year, strDateLength);
        if(isValidFormat)
        {
            isValidDate = validateDate(month, days, year);
            if(isValidDate)
            {
                fprintf(outputFile, "%s", buffer);
            }
        }
    }
    fclose(outputFile);
    return TRUE;
}
void appendNewLine(char *str, size_t strLength)
{
    str[strLength] = 'n';
    str[strLength + 1] = '';
}
int validateDateFormat(char *str, int *month, int *days, int *year, size_t strDateLength)
{
    int index, index2 = 0;
    char temp[BUFFERSIZE];
    int numOfForwSlashes = 0;
    for(index = 0; index < strDateLength; index++)
    {
        if(str[index] == '/')
        {
            if(numOfForwSlashes == 0)
            {
                *month = atoi(temp);
            }
            else if(numOfForwSlashes == 1)
            {
                *days = atoi(temp);
            }
            numOfForwSlashes++;
            memset(&temp[0], 0, sizeof(temp));
            index2 = 0;
        }
        else if(str[index] == 'n')
        {
            *year = atoi(temp);
        }
        else if(!isdigit(str[index]) && str[index] != ' ')
        {
            return FALSE;
        }
        else
        {
            temp[index2] = str[index];
            index2++;
        }
    }
    if(numOfForwSlashes != TOTALFORWARDSLASHES) // This define is 2
    {
        return FALSE;
    }
    else
        return TRUE;
}
int validateDate(int month, int days, int year)
{
    if((month < JANUARY || month > DECEMBER) && (days < 1 || days > THIRTYONE))
    {
        return FALSE;
    }
    if(month == FEBURARY)
    {
        if(isLeapYear(year))
        {
            if(days > TWENTYNINE)
            {
                return FALSE;
            }
        }
        else
        {
            if(days > TWENTYEIGHT)
            {
                return FALSE;
            }
        }
    }
    else if(month == APRIL || month == JUNE || month == SEPTEMBER || month == NOVEMBER)
    {
        if(days > THIRTY)
        {
            return FALSE;
        }
    }
    else
    {
        if(days > THIRTYONE)
        {
            return FALSE;
        }
    }
    return TRUE;
}

问题:

在大多数情况下,除了缺少年份的情况外,它都可以工作,坦率地说,我想知道是否有办法在遵循 citeria 的同时使其更简洁。使用 sscanf 或 scanf 并不能解决我遇到的所有问题,像 strtok 这样的字符串函数也没有多大帮助。

。除了缺少年份的情况外,它有效,坦率地说,我想知道是否有办法使它更简洁......

与其只创建一个函数来分析

日期,不如创建一个帮助程序函数来分析每个整数。

未经测试的代码示例:

#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
// Parse 1 int and optional following delimiter
// Return NULL on error
static const char *Get_int(const char *p, int *i, int endchar) {
  if (p) {
    char *endptr;
    errno = 0;
    long y = strtol(p, &endptr, 10);
    if (errno || p == endptr) return NULL;
    *i = y;  // Test for INT_MIN... INT_MAX if desired
    // skip following white-space
    while (isspace((unsigned char ) *endptr))
      endptr++;
    // Look for delimiter
    if (endchar) {
      if (*endptr != endchar) return NULL;
      endptr++;
    }
    return endptr;
  }
  return NULL;
}
int validateDateFormat(char *str, int *month, int *days, int *year, 
    size_t strDateLength) {
  // form string
  char temp[strDateLength + 1];
  memcpy(temp, str, strDateLength);
  temp[strDateLength] = '';
  const char *p = temp;
  p = Get_int(p, month, '/');
  p = Get_int(p, days, '/');
  p = Get_int(p, year, 0);
  return p && *p == '';
}

sscanf()方法:

使用 "%n" 检测是否扫描了整个字符串。

int validateDateFormat(char *str, int *month, int *days, int *year, 
    size_t strDateLength) {
  // form string
  char temp[strDateLength + 1];
  memcpy(temp, str, strDateLength);
  temp[strDateLength] = '';
  int n = 0;
  sscanf(temp, "%d /%d /%d %n", month, days, year, &n);
  return n > 0 && temp[n] == '';
)

黑客攻击:请注意,以下代码假定 strDateLength > 0fgets()会很乐意读入空字符作为第一个字符,并继续阅读,直到遇到'n'

由于strDateLengthsize_t,无符号类型,0-1是一个巨大的价值,buffer[strDateLength - 1]肯定会引起问题。

while(fgets(buffer, BUFFERSIZE, stdin)) {
  strDateLength = strlen(buffer);
  if(buffer[strDateLength - 1] != ...

顺便说一句,无论如何都不需要添加'n'

相关内容

  • 没有找到相关文章

最新更新