Pascal No
Pascal No

Reputation: 21

ensure that scanf only reads dd.mm.yyyy

I am looking for a solution of my problem. I want to scanf a date (dd.mm.yyyy). I need to make sure, the input is in this format with only 0 < day < 31 ; 0 < month < 13 ; 2018 < year .

For length of the Task, i do it like this:

printf("Please typ in the Task: \t");
scanf("%s", &what);
while (strlen(what) >= MAX) {
    clearScanf();
    printf("The task must contain a maximum of %d :\t", MAX - 1);
    scanf("%s", &what);
}

But i dont know how to ensure, that my

printf("Pls put in the Deadline (dd.mm.yyyy): \t");
scanf("%s", when);

wont take characters, but still use the '.' between.

After the scanf, i want to give everything to my structure back with:

strcpy(temp->name, what);
strcpy(temp->deadline, when);
temp->next = pointer;

But i dont know, how to give month, year and day sepeerat back.

Upvotes: 0

Views: 583

Answers (2)

Michael Beer
Michael Beer

Reputation: 850

Write your own format checking function:

bool is_correctly_formatted(const char* s) {

    if(!isdigit(s[0])) return false;
    if(!isdigit(s[1])) return false;
    if('.' != s[2]) return false;
    if(!isdigit(s[3])) return false;
    if(!isdigit(s[4])) return false;
    if('.' != s[5]) return false;
    if(!isdigit(s[6])) return false;
    if(!isdigit(s[7])) return false;
    if(0 != s[8]) return false;

    return true;

}

You can then use it like:

#define MAX 8

int main(int argc, char** argv) {

    /* Space for MAX chars + line feed + terminal zero */
    char what[MAX + 1 + 1] = {0};

    /* Ensure that scanf reads in at most as many chars as can be safely written to `what` */
    char format[MAX + 2 + 1] = {0};
    snprintf(format, sizeof(format), "%%%ds", MAX + 1);

    do {
        printf("%s Please type in the Task: ", format);
        scanf(format, &what[0]);
        /* chomp the trailing '\n' */
        if(isspace(what[MAX + 1])) what[MAX + 1] = 0;
        printf("Entered %s\n", what);
    } while (! is_correctly_formatted(what));
}

This enables you to be as flexible in what you expect as possible. You could even resort back to using some kind of regex library.

Beware: The read string will contain the trailing line feed, thus you got to remove it...

Upvotes: 0

Spikatrix
Spikatrix

Reputation: 20252

Using scanf + sscanf:

int day, month, year;
for(;;)                                        /* Infinite loop */
{
    scanf("%s", when);
    char temp;
    if(sscanf(when, "%2d.%2d.%4d%c", &day, &month, &year, &temp) != 4 ||
       temp != '\n')                           /* Check if no extra characters were typed after the date */
    {
        fputs("Invalid format!\n", stderr);
        clearScanf();                          /* Assuming this function of yours clears the stdin */
    }
    else if(!(0 < date && date <= 31) ||       /* Valid range checks */
            !(0 < month && month <= 12) ||
            !(0 < year && year <= 2018))
    {
        fputs("Invalid date!\n", stderr);
    }
    else
    {
        break;
    }
}

What this does is, it tells scanf to first scan a string and then extracts data from it using sscanf.

The sscanf first extracts 2 digits, then a dot, again two digits, a dot and then 4 digits and finally a character and assigns to the corresponding argument. The character is to check if the user typed more characters.

sscanf returns the number of items successfully scanned and assigned. In this case, if it returned 4, it successfully extracted everything.

Upvotes: 3

Related Questions