Sscanf rejects leading zeros in whole reads

I want to create a simple "date" using sscanfthat accepts input as:

"dd/mm/yyyy"

Both fields "dd" and "mm" can be equal to 2 bits (for example, 0, 6 or 11, but not 123). The years field may be a 0 or 4 digit field. A value of 0 in any of these three fields means that you should instead accept the day, month, or year of the system.

This format must be strict, therefore, if the input format does not match the template, the user must be notified.

My attempt:

int d, m, y;
char const* input = "23/7/1990";

int n = sscanf(input, "%2u/%2u/%4u", &d, &m, &y);

if (n != 3) throw InvalidDate("Invalid format");

// Fill 0 values with system date.
// Check date correctness with `mktime` and `localtime`.

The problem is that this format sscanfaccepts invalid inputs like:

char const* invalid1 = "23/ 12/ 1990";
char const* invalid2 = "23/12/1990/123whatever......."

, - / , ?

(invalid2; ) :

int d, m, y;
char trick;

char const* input = "23/7/1990";

int n = sscanf(input, "%2u/%2u/%4u%c", &d, &m, &y, &trick);

// If it fills four fields, means the input was too long.
if (fields != 3) throw InvalidDate("Invalid format");

// Fill 0 values with system date.

, end-of-string. , "" ( "% c" ) sscanf, , (, "23/6/1990" char ; if scanf sscanf, ferror ). "%2u/%2u/%4u\0", \0 .

, stringstream?

, "" sscanf?

+4
5

, . :

#include <boost/regex.hpp>
#include <iostream>
#include <string>

int main()
{
    // Expression to match
    boost::regex e("(^\\d{1,2})/(\\d{1,2})/(\\d{4})$");

    // Results are here
    boost::match_results<std::string::const_iterator>  results;

    std::string val_to_match = "1/11/1990";
    if (boost::regex_search(val_to_match, results, e) && results.size() == 4) {
        std::cout << "Matched "  << results[0] << std::endl; 
        int i = 1;
        while (i < 4) {
            std::cout << "Value: " << i <<  "  "<< results[i] << std::endl;
            i++;
        }
    } else {
        std::cout << "Couldn't match \n";
    }

    return 0;
}
+1

:

 void parseDate(const char *date) {

      char trick;
      int d, m, y, n = sscanf(date, "%2u/%2u/%4u%c", &d, &m, &y, &trick);

      (n != 3 || y < 999)) ? 
           puts("Invalid format!") : printf("%u %u %u\n", d, m, y);
 }

, "" , , , 1000-9999. , 23/7/1a990 1.

.

:

Sample date: 23/7/1990
Output: 23 7 1990

Sample date: 23/12/1990/123whatever.......
Output: Invalid format!

Sample date: 23/ 12/ 1990
Output: 23 12 1990

Sample date: 23/12/19a90
Output: Invalid format!

Sample date: 2a/1
Output: Invalid format!

Sample date: a23/12/1990
Output: Invalid format!

Sample date: 23/12/199000
Output: Invalid format!

: std::string ++?. strptime.

+1

? %[^0-9] .

#include <stdio.h>
#include <string.h>

void process_date(const char* input){
  int d, m, y;
  char sep1[3], sep2[3], trick;
  int n;

  n = sscanf(
    input, "%2u%2[^0-9]%2u%2[^0-9]%4u%c",
    &d, sep1, &m, sep2, &y, &trick);

  if(!(n == 5 && strcmp(sep1, "/") == 0 && strcmp(sep2, "/") == 0)){
    fprintf(stderr, "Invalid format (input = %s).\n", input);
    return;
  }

  printf("d = %d, m = %d, y = %d.\n", d, m, y);
}

int main(){
  process_date("23/7/1990");
  process_date("23/12/1990");
  process_date("23/7/0");
  process_date("23/0/1990");
  process_date("0/7/1990");

  process_date("23/ 12/ 1990");
  process_date("23/12/1990/123whatever.......");
  process_date("123/7/1990");
  process_date("23/12/19a90");
  process_date("2a/1");
  process_date("a23/12/1990");
  process_date("23/12/199000");

  return 0;
}

:

d = 23, m = 7, y = 1990.
d = 23, m = 12, y = 1990.
d = 23, m = 7, y = 0.
d = 23, m = 0, y = 1990.
d = 0, m = 7, y = 1990.
Invalid format (input = 23/ 12/ 1990).
Invalid format (input = 23/12/1990/123whatever.......).
Invalid format (input = 123/7/1990).
Invalid format (input = 23/12/19a90).
Invalid format (input = 2a/1).
Invalid format (input = a23/12/1990).
Invalid format (input = 23/12/199000).
+1

- ? sscanf, , , , :

int d, m, y;

int date[3];        //holds day/month/year in its cells
int tokenCount = 0;
char* pc;
int result = 0;
char* pch = strtok(input, "/");

while (pch != NULL)
{
    if (strlen(pch) == 0)
    {
        throw InvalidDate("Invalid format");
    }

    //atoi is stupid, there no way to tell whether the string didn't contain a valid integer or if it contained a zero
    result = strtol(pch, &pc, 10);
    if (*pc != 0)
    {
        throw InvalidDate("Invalid format");
    }

    if (tokenCount > 2)     //we got too many tokens
    {
        throw InvalidDate("Invalid format");
    }

    date[tokenCount] = result;
    tokenCount++;

    pch = strtok(NULL, "/");
}

if (tokenCount != 3)
{
    //not enough tokens were supplied
    throw InvalidDate("Invalid format");
}


d = date[0];
m = date[1];
y = date[2];

, , 1-12.

, strtok , , .

0

. , , , sscanf , , :

char const* input = "23/7/1990";

int d, m, y;

{ // Search blanks due to `sscanf` limitations.
    for (unsigned i = 0; i < 10 and input[i] != '\0'; ++i)
        if (isspace(input[i]))
           throw InvalidDate("Invalid format");

} { // Check format (with extra input detection).
    char trick;
    int n = sscanf(input, "%2u/%2u/%4u%c", &d, &m, &y, &trick);

    if (n != 3 or (y != 0 and y < 1000))
        throw InvalidDate("Invalid format");
}

// Fill 0 values with system date.
// Check date correctness with `mktime` and `localtime`.

EDIT: strpbrk (sscanf ). , strpbrk , -. , , . , 10-loop for, isspace.

, , , "\ 0" , " " for . , sscanf, for .

"" .

0

All Articles