Home > Blockchain >  escape character '-' in a sscanf() function
escape character '-' in a sscanf() function

Time:09-13

The problem is very simple, I have a date column in my database postgres, it returns the value as string in the format yyyy-mm-dd, in order to store it in my code, I need to parse the value. The function is also very simple:

int parse_date(const char * s, tbDate*res)
{
    int yyyy, mm, dd;
    if (sscanf(s, "%d %d %d", &yyyy, &mm, &dd) == 3
            || sscanf(s, "%d.%d.%d", &yyyy, &mm, &dd) == 3
            || sscanf(s, "%d/%d/%d", &yyyy, &mm, &dd) == 3
            || sscanf(s, "%d-%d-%d", &yyyy, &mm, &dd) == 3)
    {
        if (mm > 0 && mm < 13 && dd>0 && dd < 32)
        {
            res->day = dd;
            res->month = mm;
            res->year = yyyy;
            return TB_PARSE_SUCCESS;
        }
    }
    return TB_PARSE_FAILURE;
}

The first three versions of sscanf() work very well, but the follow sscanf(s, "%d-%d-%d", &yyyy, &mm, &dd) , the format that the database returns, are read as negative value, it means that if I pass a date like '2022-12-03', yyyy is correctly 2022, but mm and dd, are -12 and -3. I would avoid to put a date format function in the query of the database, and I would know if there is a way to escape the - charachter inside the sscanf().

CodePudding user response:

date like '2022-12-03', yyyy is correctly 2022, but mm and dd, are -12 and -3.

That is because "2022-12-03" matched sscanf(s, "%d %d %d", &yyyy, &mm, &dd) == 3 first. Note that a " " in format "%d %d %d" match 0 or more white spaces.

Simply change order

if (   sscanf(s, "%d-%d-%d", &yyyy, &mm, &dd) == 3  // swapped
    || sscanf(s, "%d.%d.%d", &yyyy, &mm, &dd) == 3
    || sscanf(s, "%d/%d/%d", &yyyy, &mm, &dd) == 3
    || sscanf(s, "%d %d %d", &yyyy, &mm, &dd) == 3) // swapped

CodePudding user response:

It comes me in mind that the sscanf() function works also if is a dirty answer for example it returns 3 also if you writes '2022/09/12fooobar', so I decided to change the function and improved the check of valid day, since I didn't find it in internet I post my own parse date function:

int parse_date(const char * s, tbDate*res)
{
    
    res->year=res->month=res->day=0;
    char separator;
    int acc=0;
    while (isspace(*s))
        s  ;
    if(!(*s >= '0' && *s <= '9'))
        return TB_PARSE_FAILURE;
    while (*s >= '0' && *s <= '9')
        acc = (acc << 3)   (acc << 1)   *s   - '0';///fast way to multiply for 10
    if(!*s) return TB_PARSE_FAILURE;
    separator=*s;
    s  ;
    res->year=acc;
    acc=0;

    if(!(*s >= '0' && *s <= '9'))
        return TB_PARSE_FAILURE;
    while (*s >= '0' && *s <= '9')
        acc = (acc << 3)   (acc << 1)   *s   - '0';
    res->month=acc;
    acc=0;
    if(*s!=separator)
            return TB_PARSE_FAILURE;
    s  ;
   if(!(*s >= '0' && *s <= '9'))
        return TB_PARSE_FAILURE;
    while (*s >= '0' && *s <= '9')
        acc = (acc << 3)   (acc << 1)   *s   - '0';
    res->day=acc;
    while(isspace(*s))
        s  ;
    if(*s) return TB_PARSE_FAILURE;
        switch (res->month)
        {
            case 1:
            case 3:
            case 5:
            case 7:
            case 8:
            case 10:
            case 12:
                if( res->day>0 && res->day<32)
                   return TB_PARSE_SUCCESS;
                else
                    return TB_PARSE_FAILURE;
            case 4:
            case 6:
            case 9:
            case 11:
               if( res->day>0 && res->day<31)
                    return TB_PARSE_SUCCESS;
                else return TB_PARSE_FAILURE;
            case 2:
               if(res->day>0 && res->day<29)
                    return TB_PARSE_SUCCESS;
                else if (res->day==29 &&(res->year@0==0 ||(res->year%4==0 && res->year0!=0)   ) )
                    return TB_PARSE_SUCCESS;
                else
                    return TB_PARSE_FAILURE;
            default:
                return TB_PARSE_FAILURE;
            }

    return TB_PARSE_FAILURE;
}

It skips spaces at begin and at the end, but not inside the numbers. It checks if you use the same separator and check if the date is valid or less.

  •  Tags:  
  • c
  • Related