سؤال

I'm fairly new to C, and I'm writing some code which will allow the user to enter the date in the form dd/mm/yyyy OR dd-mm-yyyy. I can't figure out how to get scanf to ignore the dash or slash, but not both. I need the code to recognise negative numbers after a slash is entered as well. At the moment, the program just thinks it's a dash and ignores it.

    int dd1, mm1, yyyy1;
    char str [3];
    scanf("%d %[-/] %d %[-/] %d", &dd1, str, &mm1, str, &yyyy1);

Any help will be greatly appreciated!

هل كانت مفيدة؟

المحلول 4

You could try this:

scanf(" %3d%1[/-]%3d%1[/-]%5d", ...);

Because those fields widths only specify the maximum widths, but not the minimum widths, they cannot be used to distinguish input with narrow fields. Therefore, if you want to restrict the input formats to dd/mm/yyyy or dd-mm-yyyy strictly, you need do more syntax checks after scanf() returns successfully.

Here is a test program:

#include <stdio.h>

int
main(void)
{
    int yy, mm, dd;
    char del1[2], del2[2];

    const char *dates[] = {
        /* well formed */
        "28-03-2014",
        "-28-03-2014",
        "28--03-2014",
        "28-03--2014",
        "28/03/2014",
        "-28/03/2014",
        "28/-03/2014",
        "28/03/-2014",
        /* ill formed */
        "28-3-2014",
        "8-03-2014",
        "28-03-14",
        "28-03/2014",
        "28/03-2014",
        "28 03 2014",
        NULL,
    };

    for (size_t i = 0; dates[i]; i++) {
        int ret = sscanf(dates[i], " %3d%1[/-]%3d%1[/-]%5d", &dd, del1, &mm, del2, &yy);
        if (ret != 5 || del1[0] != del2[0]) {
            fprintf(stderr, "%s : syntax error\n", dates[i]);
            continue;
        }
        printf("del = %c, yy = %d, mm = %d, dd = %d\n", del1[0], yy, mm, dd);
    }

    return 0;
}

نصائح أخرى

you can just read the input and parse it afterwards with sscanf() Sample program:

#include <stdio>
int main(void)
{
  char buf[256];
  int dd1, mm1, yyyy1;
  printf("input date: ");
  // this is normally a function for file operations, but if you define stdin,
  // the standard input, as file pointer it reads keyboard input
  fgets(buf, 256, stdin); 
  if(sscanf(buf, "%d-%d-%d", &dd1, &mm1, &yyyy1) != 3)
  {
    if(sscanf(buf, "%d/%d/%d", &dd1, &mm1, &yyyy1) != 3)
    {
      printf("Wrong format!\n");
    }
    else
    {
      printf("format with /\n");
    }
  }
  else
  {
    printf("Format with -\n");
  }
}

Ok, first you read your input with fgets(). It will maximal read 255 bytes from the standard input (which is your keyboard) and safe that into the array I called "buf". Then we use sscanf() to "analyze" the input. sscanf() returns the number of sucessfully assigned variables, as you want to read 3 numbers from the string every return value different from 3 indicates an error/wrong input. The first sscanf() checks for the date format with a - and second sscanf() checks for the date format with /

Sorry for the previous thing.

In case you don't want to use an intermediate storage, you can make your programme say "Hey! First, I want a number, then a character, then another number, then a character, and lastly one another number." which is exactly how your date string is formatted.

There are two further conditions which are that, you want both of the characters in between to be same with each other, and also either be a dash or a slash. This is how you can do that:

int dd1, mm1, yyyy1;
char sep1, sep2;

if ( scanf( "%d%c%d%c%d", &dd1, &sep1, &mm1, &sep2, &yyyy1 ) == 5 && sep1 == sep2 && ( sep1 == '/' || sep1 == '-' ) )
    printf( "Day: %d\nMonth: %d\nYear: %d", dd1, mm1, yyyy1 );
else {
    // invalid syntax
}

Exactly the way I've described above, it asks for an integer, then a character, integer, character and integer. If it cannot get all that, then it won't be returning a 5 (scanf returns the number of variables it filled). Next thing is to check whether both separators are the same; and lastly the separators have to be a dash or a slash.

Just putting this down as an alternative, there will always be another method.

The classic way to read (potential hostile) user input involves 3 steps:

  1. I/O
  2. Parsing
  3. Range verifications.

I/O:

char buffer[100];
if (fgets(buffer, sizeof buf, stdin) == NULL) Handle_EOForIOerror();

Parsing

int dd1, mm1, yyyy1;
// check the result of `sscanf()`
if (sscanf(buffer, "%2d/%2d/%4d", &dd1, &mm1, &yyyy1) != 3) ||
    sscanf(buffer, "%2d-%2d-%4d", &dd1, &mm1, &yyyy1) != 3)) FormatError();

Range verification

if (dd1 < 1 || dd1 > 31 || mm1 < 1 || mm1 > 12 || ...) Handle_RangeError();

Additional checks include

1) Looking for trailing junk

int n;
if (sscanf(buffer, "%2d/%2d/%4d %n", &dd1, &mm1, &yyyy1, &n) != 3) ||
    sscanf(buffer, "%2d-%2d-%4d %n", &dd1, &mm1, &yyyy1, &n) != 3))FormatError();
if (buffer[n] != '\0') TrailingJunkDetected();

2) if (!valid_date(yyyy1, mm1, dd1)) ...

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top