cstrtokstring.h

strtok skips more than one delimiter, how to make it skip only one


I am currently developing a parser for nmea sentences which typically go like this:

"$GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62\r\n"

So I created this function that uses strtok to parse it using the comma as delimiter and store each data field in the values array, it is important that each data field goes into the correct position in the array.

int split_string_by_comma (nmea_message_t * message_info, char ** values)
{
    int i = 0;
    char * p = strtok(message_info->data_field, MSG_DELIMITER);
    
    while (p != NULL)
    {
        values[i++] = p;
        p = strtok(NULL, MSG_DELIMITER);
    }
    return i;
}

Issue is, it is not uncommon for nmea sentences to skip certain data fields, example:

"$GPRMC,,A,,S,14507.36,E,000.0,,,,E*62\r\n"

In this case my function is useless because I want the empty data fields between the commas to be assigned to values as NULL instead of being completely ignored.

Any suggestions? Thanks!


Solution

  • strsep could be what you want:

    The strsep() function was introduced as a replacement for strtok(3),
    since the latter cannot handle empty fields.
    However, strtok(3) conforms to C89/C99 and hence is more portable.

    Its syntax is not exactly the same:

    #include  <stdio.h>
    #include  <string.h>
    
    #define MSG_DELIMITER ","
    
    void split_string_by_comma (char* msg)
    {
        int i = 0;
        char * p = strsep(&msg, MSG_DELIMITER);
    
        while (p != NULL)
        {
            printf("%d - %s\n", ++i, p);
            p = strsep(&msg, MSG_DELIMITER);
        }    
    }
    
    int main(void)
    {
        char good[] = "$GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62\r\n";
        char bad[] = "$GPRMC,,A,,S,14507.36,E,000.0,,,,E*62\r\n";
    
        split_string_by_comma(good);
        split_string_by_comma(bad);
        return 0;
    }
    

    :~/test/strsep$ ./a.out
    1 - $GPRMC
    2 - 081836
    3 - A
    4 - 3751.65
    5 - S
    6 - 14507.36
    7 - E
    8 - 000.0
    9 - 360.0
    10 - 130998
    11 - 011.3
    12 - E*62
    
    1 - $GPRMC
    2 -
    3 - A
    4 -
    5 - S
    6 - 14507.36
    7 - E
    8 - 000.0
    9 -
    10 -
    11 -
    12 - E*62